“解析JavaScript — lazy 是否比 eager更好?”
本文理论内容来自JSConf EU 2017 中“Parsing JavaScript — better lazy than
eager?”为题的主题演讲。
V8与解析器
每个JavaScript代码在浏览器中被执行,经历的的第一步就是parser,解析器。
解析器会将JavaScript源码生成AST和程序作用域(Scopes),后面就是字节码生成器生成字节码,然后编译生成机器码送入执行
浏览器在解析真实网页的时候,经测试发现,在解析阶段,一般耗费的时间占总时间的15%-20%,这个时间已经是影响网络速度的重要因素之一。尤其在目前移动端兴起的情况,移动端浏览器会花费比桌面多大约36%时间来对JavaScript进行解析。
根据google的Production Web Apps Performance Study研究得出结论,JavaScript的在解析速度大约 ~1MB/S。下面先来看看V8如何解析JavaScript。
对于V8来说,目前有两种解析器,分为
- parsers
- PreParsers
对于 parsers ,特点是full,“eager”。它会建立AST,创建完整的作用域,找出所有语法错误,用来解析那些将来会被complie的函数
对于PreParsers, 特点是 fase“lazy”。 它 会跳过那些不想被编译的函数,不会创建ast。会创建作用域,但不会在里面包含变量引用或者声明。会比上面快两倍。只会找出那些部分严格的错误,所有代码可能不会完全遵守ECMA的规范。
下面我们看看这两种解析器如何在解析 JavaScript代码时发挥作用。
let a = 0; //Top level code is eager
//IIFE
(function eager() {
...})() //Body is eager
//Top level function but not IIFE
function lazy() {
...} //Body is lazy
//Later
...lazy();
// -> eager parsed and complied now!;
我们看到所有最外层代码都会使用eager-parsing,以及所有IIFE同样采用eager-parsing。而其他函数,采用lazy-parsing来解析函数体。当你在后面调用它的时候,这个函数会被eager-parsed和编译然后被执行。
下面看看一些复杂的解析情况: