V8是谷歌编译我们的JavaScript的引擎。Firefox有自己的引擎叫做SpiderMonkey,它与V8非常相似,但存在差异。
关于V8发动机的一些事实:
- 用 C++ 编写并在 Chrome 和 Node.js 中使用(以及 Microsoft Edge 最新版本(https://www.theverge.com/2018/12/6/18128648/microsoft-edge-chrome-chromium-browser-changes))
- 执行 ECMA-262 中规定的 ECMAScript
JavaScript 旅程
那么,当我们发送我们的JavaScript来通过V8引擎进行审查时,会发生什么(这是在它被缩小,恶化和你对JavaScript代码做任何其他疯狂的事情之后)?
我创建了以下图表,显示了所有步骤,然后我们将详细讨论每个步骤:
在本文中,我们将讨论 JavaScript 代码是如何被解析的,以及如何将您的 JavaScript 尽可能多地转移到优化编译器中。 优化编译器(也称为 Turbofan)将我们的 JavaScript 代码转换为高性能机器代码,所以我们可以给出的代码越多,我们的应用程序就越快。
使用 JavaScript
因此,我们 JavaScript 代码的第一个处理是对其进行解析,让我们仔细讨论解析是什么。
有两个阶段进行分析,这些阶段是:
- Eager (full-parse) - 它立即解析每个行
- Lazy (pre-parse) - 做最低限度,解析我们需要的内容,然后留下剩下的时间
哪个更好?一切都取决于。
让我们来看看一些代码。
1// eager parse declarations right away
2const a = 1;
3const b = 2;
4
5// lazily parse this as we don't need it right away
6function add(a, b) {
7 return a + b;
8}
9
10// oh looks like we do need add so lets go back and parse it
11add(a, b);
因此,在这里,我们的变量声明将是渴望解析
,但然后我们的函数是轻松解析
。
要立即渴望分析``添加
函数,我们可以做到:
1// eager parse declarations right away
2const a = 1;
3const b = 2;
4
5// eager parse this too
6var add = (function(a, b) {
7 return a + b;
8})();
9
10// we can use this right away as we have eager parsed
11// already
12add(a, b);
这就是你使用的大多数模块是如何创建的。
内置功能
Chrome有时基本上会重写您的JavaScript,其中一个例子是插入正在使用的函数。
让我们以以下代码为例子:
1const square = (x) => { return x * x }
2
3const callFunction100Times = (func) => {
4 for(let i = 0; i < 100; i++) {
5 // the func param will be called 100 times
6 func(2)
7 }
8}
9
10callFunction100Times(square)
上面的代码将由V8引擎如下优化:
1const square = (x) => { return x * x }
2
3const callFunction100Times = (func) => {
4 for(let i = 100; i < 100; i++) {
5 // the function is inlined so we don't have
6 // to keep calling func
7 return x * x
8 }
9}
10
11callFunction100Times(square)
正如您从上面所看到的,V8基本上正在删除我们称之为func
的步骤,而不是square
的体格。
函数 inlining gotcha
有了这种方法,有一点 gotcha,让我们以以下代码为例:
1const square = (x) => { return x * x }
2const cube = (x) => { return x * x * x }
3
4const callFunction100Times = (func) => {
5 for(let i = 100; i < 100; i++) {
6 // the function is inlined so we don't have
7 // to keep calling func
8 func(2)
9 }
10}
11
12callFunction100Times(square)
13callFunction100Times(cube)
因此,这一次我们已经调用了平方
函数100
次,然后我们将调用平方
函数100
次。在平方
函数可以调用之前,我们必须首先消除callFunction100Times
的优化,因为我们已经调用了平方
函数体。
物体
至于对象,V8在帽子下有一个类型系统来区分你的对象:
垄断主义
对象具有相同的密钥,没有差异。
1// mono example
2const person = { name: 'John' }
3const person2 = { name: 'Paul' }
多元化
对象具有相似的结构,但存在一些小差异。
1// poly example
2const person = { name: 'John' }
3const person2 = { name: 'Paul', age: 27 }
宏观主义
物体是完全不同的,不能比较。
1// mega example
2const person = { name: 'John' }
3const building = { rooms: ['cafe', 'meeting room A', 'meeting room B'], doors: 27 }
所以现在我们知道V8中的不同对象,让我们看看V8如何优化我们的对象。
隐藏的班级
隐藏的类是V8如何识别我们的对象。
让我们把这一点分成步骤。
我们声明一个对象:
1const obj = { name: 'John'}
V8 将对该对象声明一个classId
。
1const objClassId = ['name', 1]
然后我们的对象被创建如下:
1const obj = {...objClassId, 'John'}
然后,当我们访问我们的对象上的名称
属性时,如下:
1obj.name
V8 做出了以下观点:
1obj[getProp(obj[0], name)]
这是V8在创建我们的对象时所经历的过程,现在让我们看看如何优化我们的对象并重复使用classIds
。
创建对象的技巧
如果可以,你应该 **在构建器中声明你的属性,这将确保对象结构保持不变,因此V8可以优化你的对象。
1class Point {
2 constructor(x,y) {
3 this.x = x
4 this.y = y
5 }
6}
7
8const p1 = new Point(11, 22) // hidden classId created
9const p2 = new Point(33, 44)
您应该 保持房地产订单不变,以以下示例为例:
1const obj = { a: 1 } // hidden class created
2obj.b = 3
3
4const obj2 = { b: 3 } // another hidden class created
5obj2.a = 1
6
7// this would be better
8const obj = { a: 1 } // hidden class created
9obj.b = 3
10
11const obj2 = { a: 1 } // hidden class is reused
12obj2.b = 3
一般优化技巧
所以现在让我们进入一些一般提示,这将有助于更好地优化您的JavaScript代码。
定义函数论点类型
当参数被传输到函数时,重要的是它们是相同的类型. Turbofan 将在 4 次尝试后放弃尝试优化您的 JavaScript,如果参数类型不同。
举以下例子:
1function add(x,y) {
2 return x + y
3}
4
5add(1,2) // monomorphic
6add('a', 'b') // polymorphic
7add(true, false)
8add({},{})
9add([],[]) // megamorphic - at this stage, 4+ tries, no optimization will happen
另一个提示是确保 在全球范围内声明类别:
1// don't do this
2function createPoint(x, y) {
3 class Point {
4 constructor(x,y) {
5 this.x = x
6 this.y = y
7 }
8 }
9
10 // new point object created every time
11 return new Point(x,y)
12}
13
14function length(point) {
15 //...
16}
结论
所以我希望你能学到一些关于V8如何在帽子下工作以及如何写出更好的优化JavaScript代码的知识。