等待承诺链有啥问题?

Posted

技术标签:

【中文标题】等待承诺链有啥问题?【英文标题】: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()”是不可能的,它必须被包裹在一些异步函数中,或者不是? 【参考方案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 会更干净。

【讨论】:

以上是关于等待承诺链有啥问题?的主要内容,如果未能解决你的问题,请参考以下文章

承诺。 return resolve() 和 resolve() 有啥区别?

赋值运算符、映射和承诺。该代码有啥问题? Javascript

为啥不等待函数作为承诺?

承诺等待得到解决而不返回

异步等待承诺上的 UnhandledPromiseRejectionWarning

等待多个承诺完成