此页面由社区从英文翻译而来。了解更多并加入 MDN Web Docs 社区。

View in English Always switch to English

Promise.withResolvers()

基线 2024
最近可用

自 March 2024 起,此特性已在最新浏览器中得到支持。但在较旧的设备或浏览器中可能无法运行。

Promise.withResolvers() 静态方法返回一个对象,其包含一个新的 Promise 对象和两个函数,用于解决或拒绝它,对应于传入给 Promise() 构造函数执行器的两个参数。

语法

js
Promise.withResolvers()

参数

无。

返回值

包含以下属性的普通对象:

promise

一个 Promise 对象。

resolve

一个函数,用于解决该 Promise。关于其语义,请参阅 Promise() 构造函数。

reject

一个函数,用于拒绝该 Promise。关于其语义,请参阅 Promise() 构造函数。

描述

Promise.withResolvers() 完全等同于以下代码:

js
let resolve, reject;
const promise = new Promise((res, rej) => {
  resolve = res;
  reject = rej;
});

只是它更简洁,并且不需要使用 let

使用 Promise.withResolvers() 关键的区别在于解决和拒绝函数现在与 Promise 本身处于同一作用域,而不是在执行器中被创建和一次性使用。这可能使得一些更高级的用例成为可能,例如在重复事件中重用它们,特别是在处理流和队列时。这通常也意味着相比在执行器内包装大量逻辑,嵌套会更少。

Promise.withResolvers() 是通用的且支持子类化,这意味着它可以在 Promise 的子类上调用,结果将包含一个该子类类型的 promise。要做到这一点,子类的构造函数必须实现与 Promise() 构造函数相同的签名——接受一个单独的 executor 函数,该函数可以用 resolvereject 回调作为参数来调用。

示例

将流转换为异步可迭代对象

Promise.withResolvers() 的使用场景是,当你有一个 promise,需要通过无法包装在 promise 执行器内的某个事件监听器来解决或拒绝。以下示例将 Node.js 的可读流转换为异步可迭代对象。这里的每个 promise 代表一个可用的数据批次,每次读取当前批次时,就会为下一个批次创建一个新的 promise。请注意,事件监听器只附加了一次,但实际上每次都调用了不同版本的 resolvereject 函数。

js
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()

Promise.withResolvers() 是一个通用方法。它可以在任何实现了与 Promise() 构造函数相同签名的构造函数上调用。例如,我们可以在一个将 console.log 作为 resolvereject 函数传入给 executor 的构造函数上调用它:

js
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 解决

规范

规范
ECMAScript® 2027 Language Specification
# sec-promise.withResolvers

浏览器兼容性

参见