配合V8 有效优化代码

1,481 阅读2分钟

「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」。

V8 是目前效率最高的浏览器引擎,也是 nodejs 采用的引擎

1. V8 编译原理

js -> Parse it -> AST(Abstract Syntax Tree) 抽象语法树 -> Interpreter (解释器理解抽象语法树)-> Optimising Compiler(编译器优化)[1]-> machine Code -> Bytecode

注:[1]有时候自己的优化可能不合适,当他发现运行不合适时,会发生逆优化,把刚才做的优化去掉,反而降低了我们运行的效率(代码层面尽量满足他的优化的条件,按照编译器期望的去书写,回避可能造成返优化的情况)

image.png

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
}

image.png

2.2 类型未发生变化时 运行耗时

我们上面类型变化的代码 注释掉,再重新运行,得出如下结果

注:单次执行可能存在误差,可以多执行几次,取平均值

PerformanceEntry {
  name: '测量1',
  entryType: 'measure',
  startTime: 40.301747,
  duration: 5.263503
}

image.png

可以看明显的速度提升,同样进行多次相加,但是类型没有发生变化,对代码进行了优化 如果类型发生了变化,会触发V8 的反优化,增加耗时。

3. 抽象语法树

  • 源码 -> 抽象语法树 -> 字节码 Bytecode -> 机器码
  • 编译过程会进行优化
  • 运行时可能发生反优化

4. V8优化机制

当然肯定不止下面三个,但是下面三个比较好,后面自己开发中可以参考其思想

4.1 脚本流:

下载过程中就开始解析。

当下载超过30kb的时候就新开单独线程去解析,等全部加载好之后,在进行解析时,之前的已经解析过的合并过来,减少解析时间。

4.2 字节码缓存:

源码翻译成字节码之后,例如在不同页面存在部分相同的片段,就把它缓存起来

4.3 懒解析:

针对函数,先不解析内部逻辑,真正用时再解析。

说到这里,大家可以检查下自己的代码中时候有类型的代码,可以进行优化下·~~

这里也可以看出,ts的引入会让我们解决一些类型转换的问题。。