如果我显式 return Promise,我应该定义异步函数吗?

Should I define async function if I explicitly return a Promise?

我们知道 async 函数 return 是一个隐含的 Promise。但我有一个纯粹迂腐的问题。如果我明确地 return 一个 Promise,我应该放一个 async 关键字吗?

这是:

const wait = async ms => new Promise(
    resolve => setTimeout(resolve, ms)
);

有什么不同吗?

const wait = ms => new Promise(
    resolve => setTimeout(resolve, ms)
);

我相信从技术上讲它们是相同的。这两种定义这种功能的方法背后是否有任何风格指南或官方推荐?

我考虑使用 async 函数的主要原因有四个:

  1. 您想使用 await.
  2. 您希望它自动捕获同步异常并将它们变成被拒绝的承诺。
  3. 你希望它总是return一个承诺,不管你的函数实际上是什么return。
  4. 您喜欢这样一个事实,即使函数 async 让查看代码的调用者清楚地知道该函数始终 return 是一个承诺 - 本质上是自我记录。

因此,如果您没有使用 await 并且您不需要第 2 点并且您已经手动 returning 了一个 promise,那么实际上不需要声明函数作为 async.


关于以上几点的更多想法。

如果您要使用 await,第 1 点需要 async。别无他法。

第 2 点和第 3 点实际上只是为了方便编程。如果您捕获自己的同步异常或确定没有同步异常并且您正在控制所有代码路径 return 一个承诺,那么 async 是没有必要的。

如果您的代码同时具有同步代码路径和异步代码路径,例如检查缓存和 returning 一个值(如果它存在于缓存中),则第 2 点和第 3 点都会出现,并且,如果不在缓存中,则发出网络请求以获取该值。如上所述,这可以在没有 async 的情况下手动编码,但是使用 async 有时代码会更简单一些,因为它会自动捕获您的同步异常并自动将 return 值包装在一个承诺。

第 4 点只是一种编码风格偏好。如果您喜欢制作函数 async 的“自我记录”方面,您可以这样做表明它始终 return 是一个承诺。


而且,对于任何对 async 函数如何在内部工作并经过多年优化的大量技术细节感兴趣的人来说,这是一篇关于该主题的相当深入的文章:V8 blog on fast async

在给定的示例中,async 关键字实际上只是将 return 值包装在 Promise.resolve() 中。见 async function documentation.

所以一方面你有:

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

而另一方面你有:

const wait = async ms => new Promise(resolve => setTimeout(resolve, ms));
// is similar to
const wait = ms => Promise.resolve(new Promise(resolve => setTimeout(resolve, ms)));

它们本质上是相同的,我个人会选择没有 async 关键字的变体。

Note:

Even though the return value of an async function behaves as if it's wrapped in a Promise.resolve, they are not equivalent.

An async function will return a different reference, whereas Promise.resolve returns the same reference if the given value is a promise.

It can be a problem when you want to check the equality of a promise and a return value of an async function.

const p = new Promise((res, rej) => {
  res(1);
})

async function asyncReturn() {
  return p;
}

function basicReturn() {
  return Promise.resolve(p);
}

console.log(p === basicReturn()); // true
console.log(p === asyncReturn()); // false