译:用 Promise.try 改进错误处理以及同异步的互操作性

原文:https://pawelgrzybek.com/promise-try-to-improve-error-handling-and-sync-async-interoperability/
作者:Paweł Grzybek
译者:ChatGPT 4 Turbo

编者注:Promise.try 可接收同步或异步函数,然后做统一的错误处理。这等同于 new Promise(resolve => resolve(f())),相比 Promise.resolve().then(f) 会少浪费一个 tick。

几个月前,我发表了一篇 “Deferred JavaScript promises using Promise.withResolvers 的文章,解释了一种现代的方式来处理自 JavaScript Promises 以来就存在的一项繁琐工作。随着规范增加简化程序的特性,今天我们来谈谈即将到来的 Promise.try,它正在快速通过 ECMAScript 提案阶段。

假设我们有两个函数,一个返回 promise,另一个同步返回值,我们可以这样混合使用它们:

const retSync = () => "sync return";
const retAsync = () => new Promise((r) => r("async return"));

(async () =>
  retAsync()
    .then(console.log)
    .then(retSync)
    .then(console.log)
    .catch(console.error))();

// async return
// sync return

我们换一下顺序,先放一个同步函数。

// 🚨 这行不通

const retSync = () => "sync return";
const retAsync = () => new Promise((r) => r("async return"));

(async () =>
  retSync()
    .then(console.log)
    .then(retAsync)
    .then(console.log)
    .catch(console.error))();

// TypeError: retSync().then 不是一个函数。(在 'retSync().then(console.log)' 中,'retSync().then' 是 undefined)

我们不能那么做,因为 retSync 的返回值不是一个 thenable promise。我们需要将同步返回的函数包裹在一个 promise 中。

const retSync = () => "sync return";
const retAsync = () => new Promise((r) => r("async return"));

(async () =>
  Promise.resolve()
    .then(retSync)
    .then(console.log)
    .then(retAsync)
    .then(console.log)
    .catch(console.error))();

// sync return
// async return

这样可以运行,但我们浪费了一个事件循环周期。不过,有办法解决这个问题!

const retSync = () => "sync return";
const retAsync = () => new Promise((r) => r("async return"));

(async () =>
  new Promise((resolve) => resolve(retSync()))
    .then(console.log)
    .then(retAsync)
    .then(console.log)
    .catch(console.error))();

// sync return
// async return

最后,但这不是很累人吗?如果能在不关心事物是同步还是异步的情况下混合使用它们,那就太棒了。此外,一个常见的 catch 子句用于在一个地方处理错误,无需为同步和异步执行分别编写错误处理代码是很方便的。

生态系统中已经有很多解决方案: p-try 来自 Sindre SorhusBluebird Promise.try/Promise.attemptes6-promise-try,仅举几例。另外,还有一个原生的 Promise.try 正在 ECMAScript 提案阶段中推进,我相信它很快就会成为语言规范的一部分。

const retSync = () => "sync return";
const retAsync = () => new Promise((r) => r("async return"));

(async () =>
  Promise.try(retSync)
    .then(console.log)
    .then(retAsync)
    .then(console.log)
    .catch(console.error))();

// sync return
// async return

希望这篇文章帮助你理解了 Promise.try 想要解决的目的和类型问题。继续编码,下次我会 catch("you") 👋