探秘 Node.js 10 新功能的背后:V8 release 6.6

每六周,咱们都会建立一个 V8 的新分支,做为咱们发布流程的一部分。每一个版本都是在 Chrome Beta 里程碑以前从 V8 的 Git master 分支出来的。今天(2018-03-27),咱们很高兴地宣布,咱们发布了一个新的分支:V8 version 6.6,在几个星期内,咱们会发布 Chrome 66 Stable 版,在此以前它依然处于测试阶段。V8 v6.6 提供了面向开发人员的一些很酷的特性。本文提供了预期发布的一些亮点预览。javascript

JavaScript 语言新特性

Function.prototype.toString() 如今返回源代码的全部内容,包括空格和注释。如下是一个旧行为和新行为的对比例子:html

// 注意 `function` 关键词以前的注释以及空格
function /* a comment */ foo () {}

// 以前版本:
foo.toString();
// → 'function foo() {}'
//             ^ no comment
//                ^ no space

// 新版本:
foo.toString();
// → 'function /* comment */ foo () {}'

行分隔符(U+2028)和段落分隔符(U+2029)如今容许出如今字符串文字中,matching JSON。之前,这些符号被视为字符串中的行结束符,所以使用它们会致使 SyntaxError 异常。java

在异常捕获的 catch 子句中能够不加参数: catch 的参数能够省略了 optional-catch-binding。若是您不须要在异常代码中处理 exception 对象,这很是有用。git

try {
  doSomethingThatMightThrow();
} catch { // → Look mom, no binding!
  handleException();
}

除了 String.prototype.trim() 外,V8 如今实现了 String.prototype.trimStart()String.prototype.trimEnd()。此功能之前是经过非标准 trimLeft()trimRight() 方法提供的,这些方法仍然是新方法的别名,用于向后兼容。github

const string = '  hello world  ';
string.trimStart();
// → 'hello world  '
string.trimEnd();
// → '  hello world'
string.trim();
// → 'hello world'

Array.prototype.values() 方法返回了数组的迭代接口,就像 ES2015 的 MapSet 同样:如今咱们可使用 keysvaluesentries 进行遍历。此更改有可能与现有的 JavaScript 代码不兼容。若是您发现某个网站有奇怪的行为或代码运行中断了,请尝试经过 chrome://flags/#enable-array-prototype-values 禁用此功能,并提出问题chrome

缓存执行过的代码

“冷加载(cold load)”和“温加载(warm load)”这两个术语在关于加载性能方面是众所周知的。在 V8 中,还有热加载(hot load)的概念。咱们以 Chrome 为例说明加载的不一样级别:json

  • 冷加载(cold load):Chrome 首次看到访问的网页,而且根本没有任何数据缓存。
  • 温加载(warm load):Chrome 会记住网页已被访问,而且能够从缓存中检索某些资源(例如图像和脚本源文件)。V8 意识到页面使用了相同的脚本文件,所以将编译后的代码与脚本文件一块儿缓存在磁盘缓存中。
  • 热加载(hot load):Chrome 第三次访问网页时,从磁盘缓存载入脚本文件时,它还向 V8 提供上次加载期间缓存的代码。V8 可使用这个缓存代码来避免必须从头开始解析和编译脚本。

在 V8 v6.6 以前,咱们在顶层编译后当即缓存生成的代码。V8 只编译已知在顶层编译过程当中当即执行的函数,并将其余函数标记为延迟编译。这意味着缓存代码只包含顶级代码,而全部其余函数必须在每次页面加载时从头开始进行延迟编译。从版本 6.6 开始,V8 会缓存顶级代码执行以后的脚本生成的代码。在咱们执行脚本时,更多的函数会被编译而且能够被包含在缓存中。所以,这些函数不须要在将来页面加载时编译,从而将热加载(hot load)场景中的编译和解析时间缩短 20-60%。对最终用户可见的是,提供了一个不太拥挤的主线程,所以会更顺畅,并且有更快的加载体验。api

以后咱们会编写此主题相关的详细博客文章。(已经发布并翻译:V8 6.6 进一步改进缓存性能数组

后台编译

一段时间以来,V8 已经可以在后台线程上解析 JavaScript 代码。随着去年发布的 V8 新的 Ignition 字节码解释器,咱们扩展了这个功能,以便在后台线程上将 JavaScript 源代码编译为字节码。这使得嵌入 V8 引擎的软件能够在主线程中执行更多工做,来执行更多的 JavaScript 脚本。咱们在 Chrome 66 中启用了此功能,在一般的网站上,主线程编译时间减小了 5% 到 20%。有关更多详细信息,请参阅[此功能的最新博客文章(https://v8project.blogspot.co...promise

移除 AST 编码

去年 Ignition 和 TurboFan 推出后,咱们继续从简化编译流水线(pipeline)中获益。之前在代码解析(parsing)后还须要一个名为 "AST Numbering(AST编码)" 的阶段,用来对生成的抽象语法树中的节点进行编号,以后编译器使用此节点时能够有共同的引用点。

随着时间的推移,这个后处理过程(post-processing)已经扩展到包含其余功能:为生成器和异步函数的暂停点进行编号,收集须要迫切编译的内部函数,初始化文字字面量或检测不可优化的代码模式。

经过新的流水线(pipeline),Ignition 字节码成为经常使用的引用点,而且再也不须要编号 - 可是,仍然须要其它的功能,而且仍然保留了 AST 编号。

在 V8 v6.6 中,咱们终于设法移除了其他的功能或将其移动到了其余地方,这些工做在解析过程当中完成,从而避免了对 AST 的遍历。这致使实际编译时间提升了 3-5%。

异步性能改进

咱们为 Promise 和异步函数取得了一些不错的性能改进,特别是设法缩小了异步函数和 promise 链之间的差距。

此外,异步生成器和异步迭代的性能也获得显着提升,在即将发布的 Node 10 LTS 版中会包含 V8 v6.6。

做为一个例子,考虑下面的斐波那契序列:

async function* fibonacciSequence() {
  for (let a = 0, b = 1;;) {
    yield a;
    const c = a + b;
    a = b;
    b = c;
  }
}

async function fibonacci(id, n) {
  for await (const value of fibonacciSequence()) {
    if (n-- === 0) return value;
  }
}

咱们已经测量了这种模式在 Babel transpilation 以前和以后的改进:

最后,字节码改进也提升了这些“可暂停”函数的运行时性能:生成器,异步函数和模块,并减小了它们的编译大小。咱们计划在即将发布的版本中进一步改进异步函数和异步生成器的性能,敬请关注。

数组性能改进

Array#reduce 对于 holey double arrays 吞吐量性能提升了 10 倍以上(请参阅咱们的博客文章,了解 “holey 数组”和 “packed 数组”是什么)。

不受信任的代码保护

在 V8 v6.6 中,咱们针对旁路信道漏洞采起了更多缓解措施,以防止信息泄露给不可信的 JavaScript 和 WebAssembly 代码。

再也不须要 GYP

这是第一个没有 GYP 文件的 V8 正式版本。若是您的产品须要 GYP 文件,则须要自行将它们复制到您本身的源代码库中。

内存分析

Chrome 的 DevTools 如今能够跟踪和快照 C++ DOM 对象,并显示 JavaScript 引用的全部可访问的 DOM 对象。这个特性是 V8 垃圾收集器的新 C++ 跟踪机制的好处之一。欲了解更多信息,请查看专门的博客文章:Chrome 66 使用 DevTools 跟踪 JS 对象和 DOM 对象的引用

V8 API

请使用 git log branch-heads/6.5..branch-heads/6.6 include/v8.h 获取 API 的变动列表。

对于使用 git 的 V8 开发者,能够经过 git checkout -b 6.6 -t branch-heads/6.6 签出 V8 v6.6 中的新功能进行试验。或者,您能够订阅 Chrome 的 Beta 频道,这样能够尽快尝试新功能。

相关文章
相关标签/搜索