1. 原文

V8 release v6.6

2. 摘要翻译

JavaScript language features

Function.prototype.toString()现在精确返回源码文本内容,包括了空格和注释。下面是一个新旧行为对比的例子:

// Note the comment between the `function` keyword
// and the function name, as well as the space following
// the function name.
function /* a comment */ foo () {}

// Previously:
foo.toString();
// → 'function foo() {}'
//             ^ no comment
//                ^ no space

// Now:
foo.toString();
// → 'function /* comment */ foo () {}'

行分隔符(Line separator (U+2028))和段落分隔符(paragraph separator (U+2029))现在也可以被用在字符串模板内了,和JSON相一致。之前,这些符号被当做行终结符(line terminators),因此使用它们会导致一个SyntaxError错误。

try表达式的catch块现在可以不用写参数。对于那些不需要获取错误对象的情况来说,这很有用。

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

除了String.prototype.trim()之外,V8现在还实现了String.prototype.trimStart()和String.prototype.trimEnd()。这些功能之前通过非标准的trimLeft()和trimRight()方法来提供,现在这两个方法仍旧存在,作为新方法的aliases,以保证向后兼容。

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

Array.prototype.values()方法使用和ES2015的Map和Set相同的迭代接口(iteration interface):现在keys、values、entries都可以使用同名的方法来进行迭代。这个改动可能会造成现有JS代码的不兼容。如果你在网站上发现有奇怪的和出错的代码行为,请尝试通过chrome://flags/#enable-array-prototype-values来禁用这个功能,并请提交一个错误(issue)给我们。

Code caching after execution

对于加载性能比较敏感的人来说,冷(cold)、温(warm)加载这两个术语可能比较熟悉。在V8中,还有一个被称为热(hot)加载的概念。让我们使用Chrome内嵌的V8来解释一下这几个级别的不同:

  • 冷(Cold)加载:Chrome发现被访问的站点页面是第一次加载,并且没有任何被缓存起来的数据。
  • 温(Warm)加载:Chrome发现被访问的站点曾经被访问过,并且可以从缓存中获取某些资源(e.g. 图片、脚本源文件)。V8识别到当前页面的脚本文件未被改动(shipped the same script file),因此在磁盘上缓存了编译后的代码以及脚本源文件。
  • 热(Hot)加载:当Chrome第三次访问相同的站点页面,出了从磁盘缓存中获取脚本文件(script file)之外,它也会提供V8在之前的加载中缓存起来的代码(code)。V8可以使用这些缓存起来的代码(code)来避免从头解析和编译源码文件。

在V8 v6.6版本之前,我们即刻缓存了从顶级(top-level)编译中生成出来的代码(code)。V8仅会在顶级(top-level)编译中编译那些会立刻被执行的函数,并将其他的函数标记为后续惰性编译。这意味着被缓存起来的代码仅仅包含了顶级代码(top-level code),剩下的函数不得不在其他的页面加载行为中被从头开始惰性编译。从v6.6版本开始,V8还会缓存那些在顶级编译之外的部分生成出来的代码(code)。当我们运行脚本的时候,越来越多的惰性编译内容会被加到缓存中。作为结果,这些函数也不再需要在将来的页面加载中被重新编译,这样做会减少热加载场景的代码解析和编译时长达20 - 60%。可见的用户体验变化是更少的主线程堵塞,更流畅和快速的加载体验。

我们将会专门写一篇关于这方面话题的博客。

Background compilation

从某个版本开始V8开始讲JS代码的解析工作交给后台线程处理。自从V8的新Ignition字节码解释器去年发布以来,我们开始拓展这个功能的支持范围,扩大到了将JS源码的字节码编译工作也交付给了后台线程处理。这使得主线程的工作负荷更小,解放了更多的主线程工作时间到JS代码的运行上,并减少卡顿。我们在Chrome 66中启用了该功能,作为结果,我们观测到了在典型的站点上,主线程的编译时长减少了5% - 20%。如果想要了解更多细节,请查看关于和方面话题的最新博文。

Removal of AST numbering

Ignition和TurboFan去年发布以来,从我们持续从编译管线的简化上获得收益。我们之前的编译管线有一个后解析步骤被称为”AST Numbering”,在这个步骤里生成出来的虚拟语法树里的各个节点会被编号,使得使用它的各个编译器都能获得引用(a common point of reference)。

经过一段时间,后处理步骤开始激增,添加了不少其他的功能:为生成器和async函数对suspend point(不知道怎么翻)编号,为了eager compilation收集内部函数,初始化字面量或检测未被优化的代码模式。

在新的管线之中,Ignition字节码成了引用(the common point of reference),编号这个行为不再被需要 - 但,剩余的其他功能仍旧是需要的,AST编号行为仍旧保留。

在V8 v6.6版本中,我们终于将这个遗留的功能挪走(或废弃)到其他步骤,使得我们可以移除这个遍历树行为。得到了3 - 5%的编译时长性能提升。

Asynchronous performance improvements

我们设法挤出了更多promise和async函数的性能提升,特别是设法缩小了async函数和promise链之间的性能差距。

此外,async生成器和async迭代器都得到了显著的性能提升,使得它们在将要发布的Node 10 LTS上成为了一个可行的选项,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转译的结果:

我们还计划在后续的版本中进一步提升async函数和async生成器的性能。

Array performance improvements

因holey double arrays,Array#reduce的吞吐量性能提升了超过10x(查看我们的博文来了解什么是holey & packed数组)。这拓宽了在holely & packed double arrays上应用Array#reduce的快速路径使用场景。

Untrusted code mitigations

在V8 v6.6版本中我们最终为了side-channel漏洞而落地了更多mitigations,以期防止数据泄露给未受信任的JS和WebAssembly代码。

GYP is gone

这是第一个官方发布版本中不包含GYP文件的V8版本。如果你的产品需要被删除的GYP文件,你需要手动将他们拷贝到你的代码库中。

Memory profiling

Chrome开发者工具现在可以追踪和快照C++ DOM对象,并且从JS中展示出所有可达的DOM对象和他们的引用。这个功能受益于最新的V8垃圾回收器的C++追踪机制。请阅读更详细的博文来了解更多细节信息。

V8 API

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

3. 名词解释

  • Eager compilation: every function must be compiled to bytecode already. V8 doesn’t do that out of the box, but there is a command line flag called –serialize_eager that you could turn on to force eager compilation if a code cache is being created.

EOF