【问题标题】:Should I define async function if I explicitly return a Promise?如果我明确返回一个 Promise,我应该定义异步函数吗?
【发布时间】:2021-10-22 21:43:27
【问题描述】:

我们知道async 函数会隐式返回一个 Promise。但我有一个纯粹迂腐的问题。如果我明确返回 Promise,是否应该输入 async 关键字?

这是:

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

和这个有什么不同吗?

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

我相信在技术上它们是相同的。这两种定义此类函数的方法背后是否有任何样式指南或官方推荐?

【问题讨论】:

  • 我不会,你不是 awaiting 在里面,所以这只是 IMO 的语法噪音
  • @CertainPerformance 我的一部分同意你的观点,我觉得 JavaScript 中的 async 关键字有点令人困惑。我不喜欢它只需要与await 一起使用。其他语言也是这样吗?

标签: javascript asynchronous promise es6-promise


【解决方案1】:

我认为使用async 函数的主要原因有四个:

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

因此,如果您不使用 await 并且不需要第 2 点并且您已经手动返回了一个承诺,那么实际上不需要将函数声明为 async


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

如果您要使用 await,第 1 点需要 async。没有其他办法。

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

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

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


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

【讨论】:

  • 为了可读性而添加async 怎么样?因为“await 对这个功能有意义”?
  • @RoboRobok - 我想。当然,这告诉调用者它总是会返回一个承诺,但通常你需要一些文档来告诉你函数返回什么,所以我个人不会仅仅因为这个原因而这样做。但是,这当然只是个人喜好。
  • @RoboRobok - 我决定添加第 4 点关于使其成为 async 的自我记录方面。
  • 太棒了,谢谢!另请查看下面 3limin4t0r 的答案,尤其是在底部。不确定你,但我不知道这种差异。
  • @RoboRobok - 我从来没有遇到过与特定承诺参考进行比较的问题,这样async 包装就会成为问题。我什至不知道外部调用者如何获得函数返回的承诺引用,除非它以某种方式作为参数传递给函数。无论如何,这在技术上是有区别的,只是似乎不会经常或永远不会出现。
【解决方案2】:

在给定的示例中,async 关键字本质上只是将返回值包装在 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 关键字的变体。

注意:

即使异步函数的返回值表现得好像它是 包裹在Promise.resolve 中,它们不等价。

异步函数将返回不同的引用,而 Promise.resolve 如果给定值是一个 承诺。

当你想检查一个 Promise 的相等性时,这可能是个问题 以及异步函数的返回值。

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

【讨论】:

  • 哦!文档中的相等性检查很有趣,很高兴知道这一点。
猜你喜欢
  • 2017-08-23
  • 2018-11-27
  • 2020-10-04
  • 2019-03-10
  • 2021-10-18
  • 2018-07-15
  • 2022-01-16
  • 2021-09-05
相关资源
最近更新 更多