ES 提案:Promise.try()

由 Jordan Harband 提出的 ES 提案 “Promise.try()” 正处在 stage 1。这篇博客文章解释它怎么样工作。

Promise.try()

为了了解 Promise.try() 是什么,考虑下面的代码:

function countPlusOneAsync() {
  return countAsync().then((result) => {
    return result + 1;
  });
}

如果 countAsync() 抛出一个异步异常时,countPlusOneAsync() 同样。但是我们想要的是通过 Promise 传递错误。为了解决这个问题,我们可以使用 Promise.try()

function countPlusOneAsync() {
  return Promise.try(() => { // (A)
    return countAsync(); // (B)
  }).then((result) => {
    return result + 1;
  });
}

现在行 B 抛出的异常将会被行 A 的 Promise 返回的 rejection 引导。Promise.try() 有两个额外的收益:

  • 代码的结构更加一致:所有功能现在都位于回调内部。
  • 可以控制使用什么 Promise 实现。无论 countAsync() 返回哪种 thenable,它将转换为 Promise 的实例。

替代

Promise.try() 还没有提出时,我们可以使用下面的代码变通实现:

function countPlusOneAsync() {
  return Promise.resolve()
    .then(() => { // (A)
      return countAsync();
    })
    .then((result) => {
      return result + 1;
    });
}

Promise.resolve() 创建一个结果为 undefined 的 Promise。该结果对我们不重要。重要的是我们必须由 Promise 链开始且尝试在开始于行 A 的回调函数中执行代码。

另外一个替代方法是使用 Promise 构造函数:

function countPlusOneAsync() {
  return new Promise((resolve) => {
    resolve(countAsync());
  }).then((result) => {
    return result + 1;
  });
}

FAQ

为什么不仅仅使用 async 函数?

如果可以使用 async 函数,在它的函数体内部转换所有的异常,那将是更好的选择。当然,有时候需要直接使用 Promise 编码,Promise.try() 是有用的。

为什么不只是用 new Promise()

Promise.try() 是相对小巧的异步语法糖且很容易填充(polyfill)。与 Promise 构造函数对比,Promise.try() 有下面的优势:

  • 在它的回调函数内部的代码与 .then() 回调函数一致,且更容易移除。
  • 它更具自我描述性,并且更加简洁。

扩展阅读


英文原文:https://2ality.com/2017/08/promise-try.html

Copyright © 2019 by Wu WenJun