【问题标题】:What's wrong with awaiting a promise chain?等待承诺链有什么问题?
【发布时间】:2019-06-20 11:49:15
【问题描述】:

我正在开发一个 Angular 6 应用程序,有人告诉我以下是反模式:

await someFunction().then(result => {
    console.log(result);
});

我意识到等待一个承诺链是没有意义的。如果 someFunction() 返回一个 Promise,那么如果你在等待它,你就不需要 Promise 链。你可以这样做:

const result = await someFunction();
console.log(result);

但有人告诉我,等待承诺链可能会导致错误,或者它会破坏我的代码中的东西。如果上面的第一个代码 sn-p 与第二个 sn-p 执行相同的操作,那么使用哪个代码有什么关系。第一个 sn-p 引入了哪些危险而第二个没有?

【问题讨论】:

  • 我认为顶级的“await someFunction()”是不可能的,它必须被包裹在一些异步函数中,或者不是?

标签: javascript promise async-await anti-patterns


【解决方案1】:

在底层,异步/等待只是承诺。

也就是说,当你有一些看起来像这样的代码时:

const result = await myAsyncFunction();   
console.log(result): 

这和写的一模一样:

myAsyncFunction().then(data => {
   const result = data; 
   console.log(result); 
}); 

那么原因 - 你不应该混合 async/await 和 .then 链 - 是因为它令人困惑。

最好只选择一种风格并坚持下去。

当您选择一个时 - 您不妨选择 async/await - 它更容易理解。

【讨论】:

  • it's more understandable 这是 100% 的意见。我发现很难向某些人解释 async 函数实际上在第一个 await 表达式处返回给调用者。在我看来,仅 Promise 的学习曲线就比 async / await 要少。
  • 其实我认为上面的第一个代码示例是错误的,因为没有顶级的await调用。它应该包裹在一些async function()块中,否则无法执行awai ,还是我错了?在我看来,这就是 async-await 的缺点......它有点开销恕我直言......
【解决方案2】:

如果您的then 代码返回了一个承诺而不是调用console.log,那么您的第一个示例将是await,但您的第二个示例不会。

当您使用async/await 时,您将在try/catch 块中捕获您的拒绝。您的代码将更少嵌套和更清晰。

使用then 通常会导致更多的嵌套,并且更难阅读代码。

您可以await 任何东西,无论它是否返回promise。有时,这种未来证明调用的方法可能有一天会变成异步的,或者只是返回一个承诺而不声明异步。

缺点是复杂性、性能和兼容性,与收益相比,所有这些都相形见绌。

我发现,如果您在调用函数后依赖于函数的返回值,并且它是或可能最终变为异步的,请使用await 装饰调用您的函数,让您高兴,无论它是当前异步还是返回承诺。

【讨论】:

  • 为了解释一个引入错误的场景,+1。以不好的(不知道是否讽刺?)建议作为结论,-1。
  • 我看不出这有什么讽刺意味。你是那些async/await 的仇恨者之一吗?我已经教了数百名学生使用它们,然后再也不会回去了。
  • So decorate your code with await to your heart's delight! 似乎非常暗示在不必要时使用它,尤其是与您之前的断言相结合时,您可以await 任何东西。那么,我应该var foo = await "bar"; 仅仅因为它有效吗?也许有一天我会把那个字符串变成一个承诺?同时,我必须把它放在一个async 函数中,因为我想将一个随机的await 表达式粘贴到“面向未来”的东西上。是的,我很可笑,但是当我阅读您答案末尾的声明时,这听起来仍然像讽刺。
  • 是的。如果函数返回一个定义then() 函数的对象,awaiting 它与returning 它完全不同。这确实是有害且不兼容的行为。
  • "foo() 是同步的,但有朝一日可能会变成异步的" - 这不是使用 await 的好理由,将其视为今天已经是异步的。函数是否异步是其 API 契约的重要组成部分,不能随意更改。记录你正在做的事情并坚持下去。
【解决方案3】:

有人告诉我,等待承诺链会破坏我的代码。

不一定,你的两个代码 sn-ps 确实工作相同(只要someFunction() 真的返回一个承诺)。

使用哪一个有什么关系。第一个 sn-p 引入了哪些危险而第二个没有?

很难理解和维护,混合不同的风格会让人困惑。混乱导致错误。

考虑到您需要在console.log() 调用的位置添加另一个promise 调用,甚至是函数的条件返回。你能像在函数的其他地方一样在回调中使用await吗,你需要return来自then回调的结果,甚至可以从外部函数中使用return吗?所有这些问题甚至都不会出现在第一个 sn-p 中。虽然对于您的玩具示例可以很容易地回答它们,但在具有更复杂和嵌套控制流的实际代码中可能并不容易。

所以你应该更喜欢更简洁和干净的那个。坚持await 以获得一致性,避免thenasync functions1

1:当然,规则总有例外。我会说在某些情况下使用catch 或第二个then 回调,use promise chaining for error handling 会更干净。

【讨论】:

    猜你喜欢
    • 2019-04-29
    • 1970-01-01
    • 2021-02-25
    • 2021-10-07
    • 2021-05-25
    • 1970-01-01
    • 2013-09-16
    • 2021-11-09
    • 2018-10-17
    相关资源
    最近更新 更多