原文: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/try
Promise.try()
是一个静态方法,用于处理各种回调(同步或异步,返回或异常)的结果,并将其封装为 Promise。
语法
Promise.try(func)
Promise.try(func, arg1)
Promise.try(func, arg1, arg2)
Promise.try(func, arg1, arg2, /* …, */ argN)
参数说明
func
回调的方法 (可以传入参数),可以是同步或异步,可以返回或抛出异常,也可以返回 Promise。
arg1, arg2, …, argN
方法传入的参数
返回值
返回一个 Promise 对象
- 如果
func
是一个同步方法且返回一个值,则Promise
对象的状态将是fulfilled
。 - 如果
func
是一个同步方法且抛出一个异常,则Promise
对象的状态将是rejected
。 - 如果
func
返回一个Promise
,且该Promise
已经被fulfilled
或rejected
,则Promise
对象的状态将与该Promise
相同。
说明
假设有一个 API 需要处理一个回调函数,这个回调可能是同步的,也可能是异步的。我们希望将其结果同一的封装为 Promise,最直接的方法可能是 Promise.resolve(func())
。但是,如果 func()
同步地抛出一个错误,这个错误不会被捕获,而是直接导致 Promise
对象变为 rejected
。
通常的解决方法(将函数结果提升为 Promise)是:
new Promise((resolve) => resolve(func()));
但是 Promise.try
提供了一个更简洁的写法
Promise.try(func);
通过 Promise()
构造器,错误从执行器中被抛出,并被捕捉将其转换为拒绝,因此这两种方法在大部分情况下是等价的,除了 Promise.try()
更简洁易读。
但是尽管相似,但是在下面这种情况下两者是不同的:
Promise.resolve().then(func);
区别在于 then()
方法的回调函数总是异步执行,而 Promise()
构造器的执行器总是同步执行。Promise.try()
也会同步执行函数,如果可以的话,会立即将 Promise 状态设置为 fulfilled
。
Promise.try()
可以接 catch()
和 finally()
方法,用于处理同步或异步的错误,并使 Promise 错误处理看起来像同步错误处理。
像 setTimeout()
一样,Promise.try()
也可以接受额外的参数,这些参数将被传递给回调。这意味着,与下面这样做是等价的:
Promise.try(() => func(arg1, arg2));
也可以这样
Promise.try(func, arg1, arg2);
尽管这两种写法是等价的,但是第二种写法更简洁,并且可以避免创建额外的闭包。
示例
使用 Promise.try()
下面是一个示例,展示了如何使用 Promise.try()
来处理同步或异步的结果,并将结果提升为 Promise, 并支持异常处理。
function doSomething(action) {
return Promise.try(action)
.then((result) => console.log(result))
.catch((error) => console.error(error))
.finally(() => console.log("Done"));
}
doSomething(() => "Sync result");
doSomething(() => {
throw new Error("Sync error");
});
doSomething(async () => "Async result");
doSomething(async () => {
throw new Error("Async error");
});
如果使用 async/await
,可以这样写:
async function doSomething(action) {
try {
const result = await action();
console.log(result);
} catch (error) {
console.error(error);
} finally {
console.log("Done");
}
}
在非 Promise 构造器上调用 try()
Promise.try()
是通用的方法,可以被调用在任何实现与 Promise() 构造器相同签名的构造器上。
以下是对 Promise.try() 的类似的实现(但不推荐作为 polyfill 使用)
Promise.try = function (func) {
return new this((resolve, reject) => {
try {
resolve(func());
} catch (error) {
reject(error);
}
});
};
由于 Promise.try()
实现方式(即 try...catch),可以安全地调用 Promise.try()
并将它的 this
指向任何自定义构造器,而永远不会同步抛出错误。
class NotPromise {
constructor(executor) {
// The "resolve" and "reject" functions behave nothing like the native
// promise's, but Promise.try() just calls resolve
executor(
(value) => console.log("Resolved", value),
(reason) => console.log("Rejected", reason),
);
}
}
const p = Promise.try.call(NotPromise, () => "hello");
// Logs: Resolved hello
const p2 = Promise.try.call(NotPromise, () => {
throw new Error("oops");
});
// Logs: Rejected Error: oops
与 Promise() 构造器不同,NotPromise() 构造器在运行执行器时不去处理异常。尽管如此,Promise.try() 仍然捕获异常并将其传递给 reject() 以便记录。