异步堆栈跟踪:为什么 await 击败了 Promise#then()
与直接使用 promises 相比,async
和 await
不仅可以使开发人员的代码更具可读性——它们还可以在 JavaScript 引擎中实现一些有趣的优化! 这篇文章是关于这样一种优化,涉及异步代码的堆栈跟踪。
await
和 vanilla promises
的根本区别在于 await X()
暂停当前函数的执行,而 promise.then(X)
在将 X 调用添加到回调链后继续执行当前函数。 在堆栈跟踪的上下文中,这种差异非常显着。
当 promise
链在任何时候抛出未处理的异常时,JavaScript 引擎会显示错误消息和(希望如此)有用的堆栈跟踪。 作为一名开发人员,无论我们使用普通的 promise
还是 async
和 await
,我们都期望这一点。关于 promise 也可以参考我们之前的如何创建自己的 Promise这篇文章。
Vanilla promise
想象一个场景,当对异步函数 b
的调用解析时调用函数 c
:
const a = () => {
b().then(() => c());
};
调用 a 时,会同步发生以下情况:
-
b
被调用并返回一个promise
,该promise
将在未来某个时候解决。 -
.then
回调(实际上是调用c()
)被添加到回调链中(或者,用 V8 术语来说:[...]
被添加为解析处理程序)。
之后,我们就完成了函数 a 中的代码的执行。 a 永远不会挂起,并且在对 b 的异步调用解决时上下文已经消失。 想象一下如果 b(或 c)异步抛出异常会发生什么。 堆栈跟踪应该包括 a,因为那是调用 b(或 c)的地方,对吗? 既然我们不再提及 a ,那怎么可能呢?
为了让它工作,JavaScript 引擎需要在上述步骤之外做一些事情:它在它仍有机会的时间内捕获并存储堆栈跟踪。 在 V8 中,堆栈跟踪附加到 b 返回的 promise
。 当 promise
执行时,堆栈跟踪将被传递,以便 c 可以根据需要使用它。
捕获堆栈跟踪需要时间(即降低性能); 存储这些堆栈跟踪需要内存。
async/await
这是同一个程序,使用 async/await
而不是 vanilla promises 编写:
const a = async () => {
await b();
c();
};
使用 await
,即使我们没有在 await
调用时收集堆栈跟踪,我们也可以恢复调用链。 这是可能的,因为 a 被挂起,等待 b 解析。 如果 b 抛出异常,则可以通过这种方式按需重建堆栈跟踪。 如果 c 抛出异常,则可以像同步函数一样构建堆栈跟踪,因为我们仍在发生这种情况的时候。
建议
与大多数看似“只是语法糖”的 ECMAScript 功能一样,async/await
不止于此。
遵循以下建议,使 JavaScript 引擎能够以更高效和内存效率更高的方式处理堆栈跟踪:
-
比 vanilla promises 更喜欢
async/await
。 -
使用
@babel/preset-env
避免不必要地转译async/await
。
尽管 V8 尚未实现此优化,但遵循此建议可确保我们(或其他 JavaScript 引擎)实现后的最佳性能。
相关文章
C# 中的 async 和 await
发布时间:2024/02/03 浏览次数:116 分类:编程语言
-
async 和 await 关键字用于 C# 中的异步编程。C# 中的异步编程 如果同步应用程序中有任何进程被阻止,则整个应用程序将被阻止并停止响应
Python 中的 Promise 系列
发布时间:2023/06/19 浏览次数:367 分类:Python
-
本篇文章将介绍如何用 Python 编写一系列 promise。 首先,我们将讨论 Python 中的异步编程。接下来,我们将讨论 Python 中的回调函数。
在 Python Lambda 中使用 Await
发布时间:2023/06/13 浏览次数:165 分类:Python
-
在 Python 中,要实现异步编程,我们可以将 async/await 特性与函数一起使用,但我们使用 lambda 函数来实现。 本文将讨论在 Python lambda 函数中使用 await 的可能性。Python Lamda 中没有async/await lambda
在 TypeScript 中返回一个 Promise
发布时间:2023/03/19 浏览次数:586 分类:TypeScript
-
本教程讨论如何在 TypeScript 中返回正确的 Promise。这将提供 TypeScript 中 Returns Promise 的完整编码示例,并完整演示每个步骤。
在 JavaScript 中等待 Promise 得到解决
发布时间:2023/03/10 浏览次数:826 分类:JavaScript
-
在本文中,我们将研究如何在执行 JavaScript 中的下一部分代码之前等待 Promise 得到解决。
深度理解 ES6 Promise
发布时间:2023/03/07 浏览次数:159 分类:WEB前端
-
现在我们开始 ES6 深度系列。 如果大家以前从未来到过这里,请从 ES6 教程 开始。 这篇是关于 ES6 中的 Promise API。 如果觉得该动画非常复杂,请继续阅读! Promises 是一个非常复杂的范
如何解决 TypeScript 中 Type 'Promise' is not assignable to type 错误
发布时间:2023/01/31 浏览次数:4682 分类:TypeScript
-
当我们尝试将具有 Promise 类型的值分配给具有不兼容类型的值时,会发生 Type Promise is not assignable to type 错误。 要解决错误,需要在赋值之前解决 Promise 并使两个兼容类型的值。 下面是
JavaScript 中检查函数是否返回的 Promise
发布时间:2022/12/15 浏览次数:847 分类:JavaScript
-
要检查函数是否返回 Promise ,请检查函数是否异步或调用它并检查函数是否返回具有函数类型 then 属性的对象。 如果满足任一条件,该函数将返回一个 Promise 。 // ✅ Promise check functio