首页
学习
活动
专区
圈层
工具
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Promise 这个新 API 真香!

• Hey, 我是 沉浸式趣谈

• 本文首发于【沉浸式趣谈】,我的个人博客https://yaolifeng.com也同步更新。

• 转载请在文章开头注明出处和版权信息。

• 如果本文对您有所帮助,请点赞评论转发,支持一下,谢谢!

聊到异步,Promise大家肯定都不陌生,是咱们处理异步操作的神器

不过呢,就算有Promise,有时候处理一些既可能是同步又可能是异步的函数,或者那种随时可能在启动时就给你扔个同步错误的函数,还是有点小别扭。

你懂的,就是那种“我想用.then().catch()一把梭,但又怕它在Promise链开始前就崩了”的尴尬。

好消息来了!

ES2025 憋了个大招 ——Promise.try()。

Promise.try() 到底是何方神圣?

说白了,它就是Promise上的一个静态方法,像个万能启动器。

你扔给它一个函数(管它是同步的、异步的,会返回值还是会抛错),它都能稳稳地给你包成一个 Promise。

代码大概长这样:

Promise.try(你要运行的函数, ...可能需要的参数);

简单粗暴,对吧?

关键在于,它特别擅长处理那些“不确定性”。

比如:

• 如果你的函数是同步的,执行完直接返回值X?那Promise.try()就给你一个resolved状态、值为X的 Promise。

• 要是函数同步执行时直接throw new Error()了呢?(这种最头疼了,以前可能直接崩掉后续代码)Promise.try()会捕获这个错误,然后给你一个rejected状态的 Promise,错误就在里面,你可以用.catch()接住。简直完美!

• 那如果函数本身就返回一个异步的 Promise 呢?没问题,Promise.try()就直接用那个 Promise 的状态。

为啥我们需要这玩意儿?以前不也活得好好的?

嗯... 活得好是好,但可能不够优雅,或者说,不够省心。

记得以前咱们想统一处理同步/异步函数时,可能会用Promise.resolve().then(func)这招吗?

const f = () => console.log('我应该立刻执行!');

Promise.resolve().then(f); // 但它被塞到微任务队列里去了

console.log('我先执行了...');

// 输出:

// 我先执行了...

// 我应该立刻执行!

明明f是个同步函数,结果被then这么一搞,硬生生变成了异步执行。

有时候我们并不想要这种延迟。而且,如果f本身在执行前就抛错,Promise.resolve()可管不了。

Promise.try()就是来解决这个痛点的。

它能让你的函数(如果是同步的)基本上是立即尝试执行,同时还保证了无论如何你都能拿到一个 Promise,并且同步错误也能被链式捕获。

...呃,或者更准确地说,它提供了一个统一的、更安全的 Promise 启动方式。

来,上代码感受下

搞定同步函数:

const syncTask = () => {

  console.log('同步任务跑起来~');

  return '同步搞定';

};

Promise.try(syncTask)

  .then(res => console.log('结果:', res)) // 立刻输出 "同步搞定"

  .catch(err => console.error('出错了?', err));

// 控制台会先打印 "同步任务跑起来~",然后是 "结果: 同步搞定"

处理异步函数(这个没啥特别,就是正常用):

const asyncTask = () => new Promise(resolve => setTimeout(() => resolve('异步也 OK'), 500));

Promise.try(asyncTask)

  .then(res => console.log('结果:', res)) // 大约 500ms 后输出 "异步也 OK"

  .catch(err => console.error('出错了?', err));

最妙的地方:捕获同步错误

const potentiallyExplodingTask = () => {

  if (Math.random() < 0.5) {

      // 假设这里有 50% 概率直接炸

      thrownewError('Boom! 同步错误');

  }

  return'安全通过';

};

// 多试几次你就能看到效果

Promise.try(potentiallyExplodingTask)

  .then(res =>console.log('这次运气不错:', res))

  .catch(err =>console.error('捕获到错误:', err.message)); // 能抓住那个 "Boom!"

就算potentiallyExplodingTask在Promise链条“正式”开始前就同步抛错了,Promise.try()也能稳稳接住,交给你后面的.catch()处理。

这在以前,可能就直接导致程序崩溃或者需要写额外的try...catch块了。(这点我个人觉得超级实用!)

这东西有啥好的?总结一下哈:

1.入口统一:不管三七二十一,同步异步函数塞进去,出来的都是 Promise,后续处理逻辑可以写得非常一致。代码看着就清爽多了。

2.同步错误保险:这是重点!能捕获启动函数时的同步错误,塞到 Promise 链里,让你用.catch()一勺烩了。避免了裸露的try...catch或者漏抓错误的风险。

3.可读性提升:意图更明显,一看Promise.try()就知道这里是安全启动一个可能同步也可能异步的操作。

实战中能怎么玩?

调 API:fetch本身返回 Promise,但之前的 URL 处理、参数构造啥的可能是同步的,万一出错呢?

// 以前的写法

functionfetchUserData(userId) {

  try {

      // 这里的 buildApiUrl 可能会同步抛出错误

      const url = buildApiUrl(`/users/${userId}`);

      returnfetch(url).then(res => res.json());

  } catch (err) {

      returnPromise.reject(err); // 手动转换成 Promise 错误

  }

}

// 使用 Promise.try 的写法

functionfetchUserData(userId) {

  returnPromise.try(() => {

      const url = buildApiUrl(`/users/${userId}`);

      returnfetch(url).then(res => res.json());

  });

}

// 调用示例

fetchUserData('123')

  .then(data =>console.log('用户数据:', data))

  .catch(err =>console.error('获取用户数据失败:', err));

• 用Promise.try(() => fetch(buildUrl(params)))就很稳。

混合任务链:比如先跑个同步任务,再根据结果跑个异步任务,用Promise.try(syncTask).then(res => Promise.try(() => asyncTask(res)))串起来就很自然。

// 假设我们有个处理用户输入的场景

functionvalidateInput(input) {

  // 同步验证,可能会抛出错误

  if (!input || input.length < 3) {

      thrownewError('输入太短了!');

  }

  return input.trim().toLowerCase();

}

functionsaveToDatabase(processedInput) {

  // 异步保存,返回 Promise

  returnnewPromise((resolve, reject) => {

      setTimeout(() => {

          if (processedInput === 'admin') {

              reject(newError('不能使用保留关键字'));

          } else {

              resolve({ success: true, id: Date.now() });

          }

      }, 500);

  });

}

// 使用 Promise.try 组合这两个任务

functionprocessUserInput(rawInput) {

  returnPromise.try(() =>validateInput(rawInput)).then(validInput =>

      Promise.try(() =>saveToDatabase(validInput))

  );

}

// 测试不同情况

processUserInput('') // 同步错误

  .then(result =>console.log('保存成功:', result))

  .catch(err =>console.error('处理失败:', err.message));

processUserInput('admin') // 异步错误

  .then(result =>console.log('保存成功:', result))

  .catch(err =>console.error('处理失败:', err.message));

processUserInput('user123') // 成功情况

  .then(result =>console.log('保存成功:', result))

  .catch(err =>console.error('处理失败:', err.message));

数据库/文件操作:很多库的 API 设计可能五花八门,有的同步出错有的异步出错,用Promise.try包裹一下,可以简化错误处理逻辑。(当然,具体库可能有自己的最佳实践,这只是个思路)

// 假设我们有个文件操作库,它的 API 设计有点混乱

const fileOps = {

  readConfig(path) {

      // 这个方法可能同步抛错(比如路径格式不对)

      // 也可能返回 Promise(实际读取文件时)

      if (!path.endsWith('.json')) {

          thrownewError('配置文件必须是 JSON 格式');

      }

      returnnewPromise((resolve, reject) => {

          setTimeout(() => {

              if (path.includes('nonexistent')) {

                  reject(newError('文件不存在'));

              } else {

                  resolve({ version: '1.0', settings: { theme: 'dark' } });

              }

          }, 100);

      });

  },

};

// 不使用 Promise.try 的话,调用方需要自己处理同步错误

functionloadAppConfig_old(configPath) {

  try {

      return fileOps.readConfig(configPath).then(config => {

          console.log('配置加载成功');

          return config;

      });

  } catch (err) {

      console.error('同步错误:', err);

      returnPromise.reject(err);

  }

}

// 使用 Promise.try,代码更简洁,错误处理更统一

functionloadAppConfig(configPath) {

  returnPromise.try(() => fileOps.readConfig(configPath)).then(config => {

      console.log('配置加载成功');

      return config;

  });

}

// 测试各种情况

loadAppConfig('settings.txt') // 同步错误 - 非 JSON 文件

  .catch(err =>console.error('加载失败:', err.message));

loadAppConfig('nonexistent.json') // 异步错误 - 文件不存在

  .catch(err =>console.error('加载失败:', err.message));

loadAppConfig('settings.json') // 成功情况

  .then(config =>console.log('配置内容:', config))

  .catch(err =>console.error('加载失败:', err.message));

聊了这么多,总而言之...

Promise.try()这哥们儿,虽然看起来只是个小补充,但它解决的痛点可是实实在在的。

它让 Promise 的使用,尤其是在链条的起点上,变得更健壮、更统一。

我个人感觉,一旦大家习惯了它带来的便利(特别是那个同步错误捕获!),估计很快就会成为咱们工具箱里的常客了。

有机会的话,真得试试看!

其他好文推荐

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OkIcJFQ0wxFv68NGRzlTlmng0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券