在没有 Promise.withResolvers 之前,你可能实现了这样的代码:
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
Math.random() > 0.5 ? resolve("ok") : reject("not ok");
在 Chrome 119(发布于2023年10月31日)版本之后,可以使用以下方式实现:
const { promise, resolve, reject } = Promise.withResolvers();
Math.random() > 0.5 ? resolve("ok") : reject("not ok");
Promise.withResolvers 是一个静态方法,返回一个包含新的 Promise 对象和两个函数的对象,用于解决或拒绝该 Promise。这两个函数对应于传递给 Promise() 构造函数的执行器的两个参数。
Promise.withResolvers 的关键区别在于现在解决和拒绝函数与 Promise 对象本身处于同一作用域,而不是在执行器中创建并且只能使用一次。这使得在某些更高级的用例中可能会更加方便,例如在重复事件中重用解决和拒绝函数,特别是在处理流和队列时。这通常也意味着嵌套层级较少,而不是在执行器中包含大量逻辑。
async function* readableToAsyncIterable(stream) {
let { promise, resolve, reject } = Promise.withResolvers();
stream.on("error", (error) => reject(error));
stream.on("end", () => resolve());
stream.on("readable", () => resolve());
while (stream.readable) {
await promise;
let chunk;
while ((chunk = stream.read())) {
yield chunk;
}
({ promise, resolve, reject } = Promise.withResolvers());
}
}
在使用 Promise.withResolvers 的示例中,将 Node.js 的可读流转换为异步可迭代对象。每个 promise 代表一批可用的数据,每次读取当前批次时,将创建一个新的 promise 用于下一个批次。请注意,事件监听器只添加了一次,但实际上每次都会调用不同版本的解决和拒绝函数。
此外,Promise.withResolvers 也适用于非 Promise 构造函数。可以在任何实现了与 Promise() 构造函数相同签名的构造函数上调用它。例如,我们可以在一个将 console.log 作为解决和拒绝函数传递给执行器的构造函数上调用它。
class NotPromise {
constructor(executor) {
// “resolve”和“reject”函数和原生的 promise 的行为完全不同
// 但 Promise.withResolvers() 只是返回它们,就像是原生的 promise 一样
executor(
(value) => console.log("以", value, "解决"),
(reason) => console.log("以", reason, "拒绝"),
);
}
}
const { promise, resolve, reject } = Promise.withResolvers.call(NotPromise);
resolve("hello");
// 输出:以 hello 解决
总而言之,Promise.withResolvers 提供了一种更简洁、更高级的方式来处理 Promise 的解决和拒绝,并且支持更多灵活的用例,使代码更易于阅读和维护。