家电维修网

 找回密码
 注册
家电维修网 网站首页 电工学习 查看内容

V8中更快的异步函数和promises

2018-12-1 12:41| 发布者: 南召修电视| 查看: 1343| 评论: 0

摘要: 原文作者:Maya Lekova and Benedikt Meurer 译者:UC 国际研发 Jothy写在最前:欢迎你来到“UC国际技术”公众号,我们将为大家提供与客户端、服务端、算法、测试、数据、前端等相关的高质量技术文章,不限于原创与 ...
V8中更快的异步函数和promises


接着,第二个 PromiseReactionJob 将结果传递回 throwaway promise,并恢复暂停执行的异步函数,从 await 返回值 42。


await 的开销

总结以上所学,对于每个 await,引擎都必须创建两个额外的 promise(即使右边的表达式已经是 promise)并且它需要至少三个 microtask 队列执行。 谁知道一个简单的 await 表达式会引起这么多的开销呢?!

我们来看看这些开销来自哪里。 第一行负责封装 promise。 第二行立即用 await 得到的值 v 解开了封装。这两行带来了一个额外的 promise,同时也带来了三个 microticks 中的两个。 在 v 已经是一个 promise 的情况下(这是常见的情况,因为通常 await 的都是 promise),这中操作十分昂贵。 在不太常见的情况下,开发者 await 例如 42 的值,引擎仍然需要将它包装成一个 promise。

事实证明,规范中已经有 promiseResolve 操作,只在必要时执行封装:

此操作一样会返回 promises,并且只在必要时将其他值包装到 promises 中。 通过这种方式,你可以少用一个额外的 promise,以及 microtask 队列上的两个 tick,因为一般来说传递给 await 的值会是 promise。 这种新行为目前可以使用 V8 的 --harmony-await-optimization 标志实现(从 V8 v7.1 开始)。 我们也向 ECMAScript 规范提交了此变更,该补丁会在我们确认它与 Web 兼容之后马上打上。


以下展示了新改进的 await 是如何一步步工作的:


让我们再次假设我们 await 一个返回 42 的 promise。感谢神奇的 promiseResolve,现在 promise 只引用同一个 promise v,所以这一步中没有任何关系。 之后引擎继续像以前一样,创建 throwaway promise,生成 PromiseReactionJob 在 microtask 队列的下一个 tick 上恢复异步函数,暂停函数的执行,然后返回给调用者。



最终当所有 JavaScript 执行完成时,引擎开始运行 microtask,所以 PromiseReactionJob 被执行。 这个工作将 promise 的结果传播给 throwaway,并恢复 async 函数的执行,从 await 中产生 42。

Summary of the reduction in await overhead


假如传递给 await 的值已经是一个 promise,那么这种优化避免了创建 promise 封装器的需要,这时,我们把最少三个的 microticks 减少到了一个。 这种行为类似于 Node.js 8 的做法,不过现在它不再是 bug 了 - 它是一个正在标准化的优化!


尽管引擎完全内置,但它必须在内部创造 throwaway promise 仍然是错误的。 事实证明,throwaway promise 只是为了满足规范中内部 performPromiseThen 操作的 API 约束。



最近的 ECMAScript 规范解决了这个问题。 引擎不再需要创建 await 的 throwaway promise - 大部分情况下[2]

Comparison of await code before and after the optimizations


将 Node.js 10 中的 await 与可能在 Node.js 12 中得到优化的 await 对比,对性能的影响大致如下:

async/await 优于手写的 promise 代码。 这里的关键点是我们通过修补规范[3]显着减少了异步函数的开销 - 不仅在 V8 中,而且在所有 JavaScript 引擎中。



开发体验提升


除了性能之外,JavaScript 开发人员还关心诊断和修复问题的能力,这在处理异步代码时并没那么简单。 Chrome DevTool 支持异步堆栈跟踪,该堆栈跟踪不仅包括当前同步的部分,还包括异步部分:



这在本地开发过程中非常有用。 但是,一旦部署了应用,这种方法就无法起作用了。 在事后调试期间,你只能在日志文件中看到 Error#stack 输出,而看不到任何有关异步部分的信息。


我们最近一直在研究零成本的异步堆栈跟踪,它使用异步函数调用丰富了 Error#stack 属性。 “零成本”听起来很振奋人心是吧? 当 Chrome DevTools 功能带来重大开销时,它如何才能实现零成本? 举个例子🌰,其中 foo 异步调用了 bar ,而 bar 在 await promise 后抛出了异常:


在 Node.js 8 或 Node.js 10 中运行此代码会输出:


最新评论

  • 三相电源断零线,为什么会接二连三烧坏电器
  • 风力发电机转那么慢,一圈能发多少电?
  • 零线不带电,为什么还要拉一条?直接用地做
  • 电磁阀基础知识详解:原理、维护、选型
  • 新能源汽车DC/DC变换器及实物拆机图

QQ|门户地图|网站地图|家电维修|手机版|家电维修技术论坛 ( 蜀ICP备14030498号-16 川公网安备51102502000162号 )

GMT+8, 2025-5-23 18:44

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

返回顶部