透过 V8 引擎看 ES2015 语法 async\/await 的本质

来源:互联网 发布:手机淘宝首页如何装修 编辑:程序博客网 时间:2024/05/23 00:04

这几天 javascript 最火的新闻莫过于 koa2 发布了正式版。目前最新版本是v2.0.1,koa2 团队宣称 “只要 nodejs 还未支持 async,koa2 就一直不发布正式版”,随着 node v7.6.0 的到来,全栈工程师们期待已久的 koa2 也终于正式版了——完美支持 async 函数,优雅的解决异步回调。

这一切的功劳还要归功于 V8 引擎。知乎上关于 async 的问题又重新出现在了 timeline 上:《ES next 中 async/await proposal 实现原理是什么?》。我看到很多人在回答 async 本质是 promise、yield、generator,于是也凑热闹回答了一下,等晚上再看的时候,顿时有一种穿越感:

很早之前 V8 就已经更换了新的优化执行引擎:TurboFan,不仅仅可以优化 try/catch/finally、for...of 等之前 Crankshaft 不能优化的语法,还支持了更多的 ES2015+ features。

TurboFan 引擎不仅仅是增加了对 async 的支持,更增加了对 async、generators 优化的支持。下面是生成的二进制码和 TurboFan 执行图:

在此之前很多需要借助 babel 编译的 ES2015 新特性都得到了原生支持。

异步函数:

  1. async function* readLines(path) {

  2.  let file = await fileOpen(path);

  3.  try {

  4.    while (!file.EOF) {

  5.      yield await file.readLine();

  6.    }

  7.  } finally {

  8.    await file.close();

  9.  }

  10. }

上面的 187 个字符会被 babel 编译成 2987 个字符,代码大小增加了 650%。文件地址:https://gist.github.com/justjavac/cdfe4cc0a55744e093250b8aca6a325a

对于数组和对象的析构赋值(array destructuring)

  1. function fn() {

  2.  var [c] = data;

  3.  return c;

  4. }

bable 编译成:

  1. "use strict";

  2. var _slicedToArray = function () {...(此处省略630个字符)

  3. function fn() {

  4.  var _data = data,

  5.      _data2 = _slicedToArray(_data, 1),

  6.      c = _data2[0];

  7.  return c;

  8. }

查看完整代码会发现里面有 Crankshaft 无法优化的 try/catch/finally。而在最新 V8 里面,析构赋值几乎和数组元素直接赋值一样快:

  1. function fn() {

  2.  var c = data[0];

  3.  return c;

  4. }

其它的 ES2015+ 特性也有大幅度优化:

关注最新的 V8 引擎进展可以看看 V8 的 《ES2015 and beyond performance plan(需科学上网)》。

参考文章:

  • High-performance ES2015 and beyond

  • Async Iterators for JavaScript

  • V8’s new interpreter and compiler pipeline

  • ES2015 and beyond performance plan

最后是广告时间,欢迎加入我的圈子:

原创粉丝点击