11 延迟解析:V8是如何实现闭包的
在编译 JavaScript 代码的过程中,V8 并不会一次性将所有的 JavaScript 解析为中间代码:
- 会增加编译时间,这会严重影响到首次执行 JavaScript 代码的速度,让用户感觉到卡顿;
- 解析完成的字节码和编译之后的机器代码都会存放在内存中,一次性解析和编译所有 JavaScript 代码,这些中间代码和机器代码将会一直占用内存
主流的 JavaScript 虚拟机都实现了惰性解析:指解析器在解析的过程中,如果遇到函数声明,会跳过函数内部的代码,并不会为其生成 AST 和字节码,而仅仅生成顶层代码的 AST 和字节码。
惰性解析的过程
function foo(a, b) {
var d = 10;
var f = 10;
return d + f + a + b;
}
var a = 1;
var c = 4;
foo(1, 5);
V8 会至上而下解析这段代码,在解析过程中遇到 foo 函数,只是一个函数声明语句,V8 在这个阶段只需要将该函数转换为函数对象:
这里只是将该函数声明转换为函数对象,并没有解析和编译函数内部的代码,也不会为 foo 函数的内部代码生成抽象语法树。继续往下解析,最终生成抽象语法树结果:
代码解析完成之后,V8 便会按照顺序自上而下执行代码,首先会先执行“a=1”和“c=4”这两个赋值表达式,接下来执行 foo 函数的调用,过程是从 foo 函数对象中取出函数代码,然后和编译顶层代码一样,V8 会先编译 foo 函数的代码,编译时同样需要先将其编译为抽象语法树和字节码,然后再解释执行。
在 V8 实现惰性解析的过程中,需要支持 JavaScript 中的闭包特性。