「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」。
V8 是目前效率最高的浏览器引擎,也是 nodejs 采用的引擎
1. V8 编译原理
js -> Parse it -> AST(Abstract Syntax Tree) 抽象语法树 -> Interpreter (解释器理解抽象语法树)-> Optimising Compiler(编译器优化)[1]-> machine Code -> Bytecode
注:[1]有时候自己的优化可能不合适,当他发现运行不合适时,会发生逆优化,把刚才做的优化去掉,反而降低了我们运行的效率(代码层面尽量满足他的优化的条件,按照编译器期望的去书写,回避可能造成返优化的情况)
2. 代码实例
// node.js
const {performance, PerformanceObserver} = require('perf_hooks')
const add = (a, b) => a + b;
const num1 = 1;
const num2 = 2;
performance.mark('start')
for(let i = 0; i < 1000000; i++){
add(num1, num2)
}
add(num1, 's') // 类型发生变化
for(let i = 0; i < 1000000; i++){
add(num1, num2)
}
performance.mark('end')
const observer = new PerformanceObserver((list) => {
console.log(list.getEntries()[0]);
})
observer.observe({entryTypes: ['measure']})
performance.measure('测量1', 'start', 'end')
2.1 类型发生变化时 运行耗时
结果
PerformanceEntry {
name: '测量1',
entryType: 'measure',
startTime: 43.814592,
duration: 7.716566
}
2.2 类型未发生变化时 运行耗时
我们上面类型变化的代码 注释掉,再重新运行,得出如下结果
注:单次执行可能存在误差,可以多执行几次,取平均值
PerformanceEntry {
name: '测量1',
entryType: 'measure',
startTime: 40.301747,
duration: 5.263503
}
可以看明显的速度提升,同样进行多次相加,但是类型没有发生变化,对代码进行了优化 如果类型发生了变化,会触发V8 的反优化,增加耗时。
3. 抽象语法树
- 源码 -> 抽象语法树 -> 字节码 Bytecode -> 机器码
- 编译过程会进行优化
- 运行时可能发生反优化
4. V8优化机制
当然肯定不止下面三个,但是下面三个比较好,后面自己开发中可以参考其思想
4.1 脚本流:
下载过程中就开始解析。
当下载超过30kb的时候就新开单独线程去解析,等全部加载好之后,在进行解析时,之前的已经解析过的合并过来,减少解析时间。
4.2 字节码缓存:
源码翻译成字节码之后,例如在不同页面存在部分相同的片段,就把它缓存起来
4.3 懒解析:
针对函数,先不解析内部逻辑,真正用时再解析。
说到这里,大家可以检查下自己的代码中时候有类型的代码,可以进行优化下·~~
这里也可以看出,ts的引入会让我们解决一些类型转换的问题。。