js性能优化学习笔记3-v8引擎

127 阅读2分钟

在浏览器中存在着渲染引擎,而v8只是当中用于处理js代码的部分,在代码执行之前会经历编译过程,作用域和作用域链确认都是在编译阶段就已经完成的。

以一段 js 为例,看看 v8 引擎是如何解析的

const username = 'alishi
  1. 渲染引擎 => utf-8 chunks
  2. stream => utf-16 code utils
  3. Scanner (扫描器): 经过词法分析之后得到的 tokens 可以表示如下
[
  {"type": "Keyword", "value": "const"},
  {"type": "Identifier", "value": "username"},
  {"type": "Punctuator", "value": "="},
  {"type": "String", "value": "alishi"},
]
  1. PreParser (预解析): 比如一些定义了但是没有使用的变量和方法就会采用预解析,而不是全量解析。帮助我们跳过未被使用的代码,不生成AST,创建无变量引用和声明的 scopes(作用域),使解析速度更快。
  2. Parser (解析器): 经过语法分析之后得到 AST(抽象语法树),同时会进行语法校验,抛出所有的语法错误,并构建具体的scopes信息(变量引用声明等)
{
 "type": "Keyword""body": [
   {
     "type": "VaroableDeclaration""declarations": [
       {
         "type": "VaroableDeclarator""id": {
           "type": "Identifier""name": "username",
         },
         "init": {
           "type": "Literal""value": "alishi""raw": "alishi",
         },
       }
     ],
     "kind": "const",
   }
 ],
 "sourceType": "script",
}
// 声明时未调用,因此会被认为是不被执行的代码,进行预解析
function foo() {
  ...
}
// 声明时未调用,因此会被认为是不被执行的代码,进行预解析
function fn() {
  ...
}
// 函数立即执行,只进行一次全量解析
(function bar() {
  ...
})()
// 执行 foo,需要重新对 foo 函数进行全量解析,此时 foo 函数被解析了两次
// 如果 foo 里面调用了其他函数,那么这个函数也会被解析两次,所以要尽量避免函数嵌套
foo()
  1. Ignition (解释器) 将 AST 转为字节码 (bytecode)
  2. TurboFan (编译器) => 机器码

最后拿到机器码之后就可以执行代码了,进行堆栈处理。

学习自拉钩教育前端视频