Promise.try()和Promise.withResolvers()作用速览

这篇文章发布于 2026年01月22日,星期四,20:52,归类于 JS API。 阅读 39 次, 今日 38 次 没有评论

 

本文介绍两个Promise相关的新特性。

一、Promise.try()的作用

之前我们运行一段代码,或者一个函数,想要捕获错误的时候,往往使用的是try...catch(),对吧。

但是try...catch()呢有个小问题,那就是如果里面有异步操作,如 setTimeout、Promise 内部,那么这个错误就捕获不了。

Promise.try()的作用之一就是统一同步与异步错误处理。

例如:

try {
  new Promise(resolve => resolve(callback());
} catch (e) {
  // 错误提示
}

如果这里的callback是异步的,那么上面的实现是无法捕获错误的。

但是下面的可以:

Promise.try(callback)
  .then(result => console.log(result))
  .catch(error => console.log(error))
  .finally(() => console.log("All settled."));

//zxx: 如果使用 async/await 语法,请不要使用 Promise.try,而应改用 try/catch/finally 块

二、Promise.try()的语法

语法使用示意如下:

Promise.try(func)
Promise.try(func, arg1)
Promise.try(func, arg1, arg2)
Promise.try(func, arg1, arg2, /* …, */ argN)

会返回一个 Promise,其状态可以是:

  • 已兑现的,如果 func 同步地返回一个值。
  • 已拒绝的,如果 func 同步地抛出一个错误。
  • 异步兑现或拒绝的,如果 func 返回一个 promise。

如果回调函数有参数,该怎么办?您可以通过以下两种方式之一来处理此问题:

// 创建了额外的闭包,但是也是可以运行的
Promise.try(() => callback(param1, param2));

// 不创建闭包,同样可以运行
Promise.try(callback, param1, param2);

更推荐使用后面的用法。

兼容性

目前所有现代浏览器都已经支持了,兼容性还是不错的,不支持的浏览器也可以引入polyfill进行兼容。

Promise.try()兼容性

三、Promise.withResolvers()的作用

Promise.withResolvers() 是 ECMAScript 2024 中新增的一个静态方法,其核心作用是将 Promise 的创建与其状态控制(resolve 和 reject)解耦,允许开发者同时获得一个新的 Promise 实例以及与其绑定的、用于控制其状态的函数。

使用示意:

function createControllablePromise() {
  // 返回 { promise, resolve, reject }
  return Promise.withResolvers();
}

const { promise, resolve, reject } = createControllablePromise();

// 2秒后手动 resolve
setTimeout(() => {
  resolve('成功了!');
}, 2000);

promise.then(result => {
  console.log(result); // 应该输出: 成功了!
});

对比案例

传统实现:

function withTimeout(asyncOperation, timeoutMs) {
  // 必须预先声明变量,用于在外部存储控制函数
  let resolveRef, rejectRef;

  // 创建控制超时的Promise
  const timeoutPromise = new Promise((resolve, reject) => {
    // 在构造函数内部,将内部的resolve和reject赋值给外部变量
    resolveRef = resolve;
    rejectRef = reject;

    // 设置超时定时器
    setTimeout(() => {
      reject(new Error(`操作超时,超过 ${timeoutMs}ms`));
    }, timeoutMs);
  });

  // 执行实际的异步操作
  asyncOperation()
    .then((result) => {
      // 异步操作成功,手动解决超时Promise
      resolveRef(result);
    })
    .catch((error) => {
      // 异步操作失败,手动拒绝超时Promise
      rejectRef(error);
    });

  // 返回这个受超时控制的Promise
  return timeoutPromise;
}

改为使用Promise.withResolvers()方法后:

function withTimeout(asyncOperation, timeoutMs) {
  // 一行代码同时获得Promise实例及其控制函数
  const { promise, resolve, reject } = Promise.withResolvers();

  // 设置超时定时器
  setTimeout(() => {
    reject(new Error(`操作超时,超过 ${timeoutMs}ms`));
  }, timeoutMs);

  // 执行实际的异步操作
  asyncOperation()
    .then((result) => {
      // 异步操作成功,解决Promise
      resolve(result);
    })
    .catch((error) => {
      // 异步操作失败,拒绝Promise
      reject(error);
    });

  // 返回Promise
  return promise;
}

可以看到Promise.withResolvers()的实现代码更加简洁,此API特别适用于事件监听、流处理、队列管理、超时控制等高级异步场景。

兼容性

Promise.withResolvers()方法的的兼容性要比Promise.try()更好一些,支持更早一些,如下截图所示。

兼容性

已经快要可以放心使用了。

四、结语说明

本文介绍的两个特性都属于语法层面增强的特性,通过提供更优雅的语法,显著提升了代码的可读性、可维护性。它代表了 JavaScript 异步编程向更简洁、更直观方向演进的重要一步。

实际上,在我看来,目前很多前端特性是过盛的。

每年前端领域的新特性没有100也有80,但是在生产环境使用的,寥寥无几。

等以后AI盛行之后,更回事如此,因为AI所使用的技术实现,一定是传统的,稳健的实现方式。

所谓的更高效更简洁,很难反应到真实生产环境中。

所以,目前来看,个体的学习还是不能停止的。

好啦,就这样吧。

感谢阅读,欢迎交流!

感谢

(本篇完)

分享到:


发表评论(目前没有评论)