V8优化了新的JavaScript语言功能(2018)

2020-11-08 09:39:48

PermalLink GitHub是5000万多名开发人员的家园,他们一起工作,共同托管和审查代码、管理项目和构建软件。

报名。

本文档列出了JavaScript语言功能,并提供了有关其性能的信息。在某些情况下,它解释了为什么一个特性过去是慢的,以及它是如何被加速的。

归根结底,以前由于曲轴的限制而无法优化的大多数功能现在都是新的编译器链的一等公民,不再阻止优化。

C++/JS的语言边界是双向的,这是昂贵的(特别是。从C++回调到JS)。

直接推送绑定接收器和绑定参数,然后调用目标函数,可以进一步优化编译时间,并允许将目标函数内联到调用器中。

因此,大量使用绑定的Reaction运行时的性能提高了一倍。

开发人员应该在任何地方自由地使用绑定函数,而不必担心性能损失

下面的两个代码片段执行相同的操作,但第二个代码片段可读性更好,而且对于arr.duce是唯一的传递方式,因为它不支持像forEach和map这样作为单独的参数传递它。

//将`this`作为单独的参数arr传入MAP。直接arr将`this`映射(Convert,this)//绑定到Convert函数。贴图(转换。绑定(此)。

这需要检查是否在每次为给定对象调用instanceof时都为其定义了@@hasInstance(99%的情况下不会定义)。

最初,只要没有添加覆盖(全局保护单元),就会跳过该检查。

Js Writable类使用@@hasInstance,因此对instanceof~100倍产生了巨大的性能瓶颈,因为现在不再跳过检查。

通过避免依赖于涡轮风扇的全局保护单元,并允许内联实例码,这一性能瓶颈已被修复。

开发人员在通过@@hasInstance覆盖它的行为之前应该认真考虑,因为这个神奇的行为可能会让其他人感到困惑,但使用它不会导致性能损失。

Reflect.Apply和Reflect.Construction在V8 v6.1中获得了17倍的性能提升,因此在这一点上应该被视为性能良好

诸如MAP、For Each、Reduce、ReduceRight、Find、findIndex等数组内建函数可以内联到turbofan优化代码中,从而显著提高性能。

当涉及到与临时死区相关的检查时,Const有更多的开销,因为它没有被设置。

然而,const关键字还保证,一旦将值分配给它的槽,它就不会在将来更改。

因此,每次访问常量槽值插槽时,涡轮风扇都会跳过加载和检查这些插槽(功能上下文专门化)。

Const,像let一样,由于TDZ(临时死区)而增加了开销,因此在未经优化的代码中性能略有下降。

此外,根据语言规范,每个FORF都隐式地包装在TRY/CATCH块中,这阻止了它的优化,因为曲轴从未优化过包含TRY/CATCH语句的函数。

由于turbofan能够优化包含try/Catch语句的函数,现在完全优化成为可能。

Maps和Set都提供了forEach方法,该方法允许通过提供回调来迭代它的项

因此需要首先转换到C++,并处理转换回JavaScript所需的回调(开销很大)。

由于现在没有使用C++,这些函数可以通过turbofan进一步优化和内联。

每次调用For Each时都会创建新回调函数(不是针对每个项目,而是在教导时间运行该代码行),这可能会导致它在非优化模式下运行。

最好将该调用替换为Object.prototype.hasOwnProperty.call(obj,prop),因为这样更安全,并且避免了潜在的性能影响。

曲轴进行了两次优化,仅考虑了接收器上的快速特性,原型链不包含可枚举特性或其他特殊情况(如代理)。

常量折叠的Object.hasOwnProperty在可能的情况下调用内部为True,需要满足以下三个条件。

枚举缓存需要调整,以便turbofan知道何时可以安全地使用枚举缓存索引,以避免去优化循环(这也会影响曲轴)。

密钥累加器由支持有限For-In操作集的快速部分和支持所有复杂情况(如ES6代理)的慢速部分组成

For in加上Object.Prototype.hasOwnProperty.call(obj,prop)的正确使用,是迭代对象属性的一种非常快速的方式,因此应该用于以下情况。

纯对象子类化A类本身扩展对象{}是没有用的,因为B类{}将产生相同的结果,即使A类的构造函数与B类的构造函数具有不同的原型链。

在不需要基类的情况下,我们传递对象,如下例所示。

函数createClassBasedOn(BaseClass){返回类foo扩展BaseClass{}}类栏{}const JustFoo=createClassBasedOn(Object)const FooBar=createClassBasedOn(Bar)。

Turbofan检测对象构造函数用作基类的情况,并完全内联对象实例化。

如果没有特定的基类需要混合,并且对象是从类工厂传递来扩展的,那么类工厂不会产生任何额外的开销。

以TypedArray为参数调用Function.Prototype.Apply的速度加快了,这对String.FromCharCode的调用产生了积极影响。

只要有可能,就应该使用TyedArray,因为它允许V8比普通数组更快、更积极地应用优化

任何剩余的瓶颈都将尽快解决,因为TypeArray速度快是Webgl顺利运行的前提条件。

Object.is(v,-0)的一个用法是通过Object.is(v,-0)检查值是否为-0。

确保不修改RegExp实例或其原型,因为这会干扰应用于regex操作的优化。

V8中的原生承诺已经看到了巨大的性能改进,以及通过异步/等待使用它们。

V8公开了C++API,允许跟踪Node.js apit所使用的承诺生命周期,从而深入了解承诺的执行情况。

新的编译器链生成字节码,这些字节码将复杂的生成器控制流脱糖成更简单的本地控制流字节码。

这些生成的字节码很容易被Turbofan优化,而不需要了解任何关于发电机控制流的具体信息。

将C++位移植到CodeStubAssembler允许所有执行都发生在JavaScript运行时内部,导致运行时之间没有跳转

虽然使用代理确实会产生开销,但该开销已大幅降低,但在热代码路径中仍应避免