V8中更快的异步函数和promises
上图显示了 doxbee 的基准测试,它测量了大量使用 promise 代码的性能。 注意图表展示的是执行时间,意味着值越低越好。 并行基准测试的结果,特别强调了 Promise.all() 的性能,更令人兴奋: 我们将 Promise.all 的性能提高了 8 倍! 但是,上述基准测试是合成微基准测试。 V8 团队对该优化如何影响真实用户代码的实际性能更感兴趣。 上面的图表显示了一些流行的 HTTP 中间件框架的性能,这些框架大量使用了 promises 和异步函数。 注意此图表显示的是每秒请求数,因此与之前的图表不同,数值越高越好。 这些框架的性能在 Node.js 7(V8 v5.5)和 Node.js 10(V8 v6.8)之间的版本得到了显着提升。 这些性能改进产出了三项关键成就:
在 Node.js 8 中启用 TurboFan 后,我们的性能得到了全面提升。 我们一直在研究一款名为 Orinoco 的新垃圾回收器,它可以从主线程中剥离出垃圾回收工作,从而显著改善请求处理。 最后亦不得不提的是,Node.js 8 中有一个简单的错误导致 await 在某些情况下跳过了 microticks,从而产生了更好的性能。 该错误始于无意的违背规范,但却给了我们优化的点子。 让我们从解释该 bug 开始: 上面的程序创建了一个 fulfilled 的 promise p,并 await 其结果,但也给它绑了两个 handler。 你希望 console.log 调用以哪种顺序执行呢? 由于 p 已经 fulfilled,你可能希望它先打印 'after: await' 然后打 'tick'。 实际上,Node.js 8 会这样执行: 在Node.js 8 中 虽然这种行为看起来很直观,但按照规范的规定,它并不正确。 Node.js 10 实现了正确的行为,即先执行链式处理程序,然后继续执行异步函数。 这种“正确的行为”可以说并不是很明显,也挺令 JavaScript 开发者大吃一惊 🐳,所以我们得解释解释。 在我们深入 promise 和异步函数的奇妙世界之前,我们先了解一些基础。 >> Task VS Microtask << JavaScript 中有 task 和 microtask 的概念。 Task 处理 I/O 和计时器等事件,一次执行一个。 Microtask 为 async/await 和 promise 实现延迟执行,并在每个任务结束时执行。 总是等到 microtasks 队列被清空,事件循环执行才会返回。 task 和 microtask 的区别 详情请查看 Jake Archibald 对浏览器中 task,microtask,queue 和 schedule 的解释。 Node.js 中的任务模型与之非常相似。 文章地址: https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/ >> 异步函数<< MDN 对异步函数的解释是,一个使用隐式 promise 进行异步操作并返回其结果的函数。 异步函数旨在使异步代码看起来像同步代码,为开发者降低异步处理的复杂性。 最简单的异步函数如下所示: 当被调用时,它返回一个 promise,你可以像调用别的 promise 那样获得它的值。 只有在下次运行 microtask 时才能获得此 promise 的值。 换句话说,以上程序语义上等同于使用 Promise.resolve 获取 value: |
Powered by Discuz! X3.4
© 2001-2023 Discuz! Team.