《图解 Google V8》学习笔记Day86

代码银月使
• 阅读 732

延迟解析:V8是如何实现闭包的?

在编译JavaScript代码的过程中,V8并不会一次性将所有的JavaScript解析为中间代码,这主要是基于以下两点:
首先,如果是一次性解析和编译所有代码,会影响首次编译的时间,会大大增加用户等待时间。
其次,解析完成的字节码和编译之后的机器代码会存在内存中,一次性解析所有JavaScript会一直占用内存,影响性能。
基于以上原因,所有主流的JavaScript虚拟机都实现了惰性解析。所谓惰性解析是指解析器在解析过程中,遇到函数声明,会跳过函数内部的代码。仅生成顶层代码的AST和字节码。

惰性解析的过程

关于惰性解析,我们可以结合下面这个例子来分析下:

function foo(a,b) {
var d = 100
var f = 10
return d + f + a + b;
}
var a = 1
var c = 4
foo(1, 5)

上面这段代码由上到下解析这段代码,在解析到foo函数,由于这是一个函数声明语句,V8这个阶段知只是将这个函数转换为函数对象,如图所示:
《图解 Google V8》学习笔记Day86
然后继续往下解析,由于后续的代码都是顶层代码,所以V8会为它们生成抽象语法树,最终生成的结果如下所示:
《图解 Google V8》学习笔记Day86
解析完成之后,由上至下执行代码,执行到foo函数的调用,过程是从foo函数对象中取出函数代码,然后和编译顶层代码一样,V8会先编译foo函数的代码,编译时同样需要先将其编译为抽象语法树和字节码,然后再解释执行。

拆解闭包——JavaScript的三个特性

JavaScript中的闭包有三个基础特性。
第一,JavaScript语言允许在函数内部定义新的函数,代码如下所示:

function foo() {
    function inner() {
    }
    inner()
}

第二,可以在内部函数中访问父函数中定义的变量,代码如下所示:

var d = 20
//inner函数的父函数,词法作用域
function foo() {
    var d = 55
    //foo的内部函数
    function inner() {
        return d+2
    }
    inner()
}

第三,因为函数是一等公民,所以函数可以作为返回值,我们可以看下面这段代码:

function foo() {
    return function inner(a, b) {
        const c = a + b
        return c
    }
}
const f = foo()

以上就是和JavaScript闭包相关的三个重要特性:
可以在JavaScript函数内部定义新的函数;
内部函数中访问父函数中定义的变量;
因为JavaScript中的函数是一等公民,所以函数可以作为另外一个函数的返回值。

闭包给惰性解析带来的问题

function foo() {
    var d = 20
    return function inner(a, b) {
        const c = a + b + d
        return c
    }
}
const f = foo()

按照通用的做法,d已经被v8销毁了,但是由于存活的函数inner依然引用了foo函数中的变量d,这样就会带来两个问题:
当foo执行结束时,变量d该不该被销毁?如果不应该被销毁,那么应该采用什么策略?
如果采用了惰性解析,那么当执行到foo函数时,V8只会解析foo函数,并不会解析内部的inner函数,那么这时候V8就不知道inner函数中是否引用了foo函数的变量d。
在执行foo函数的阶段,虽然采用了惰性解析,不会解析和执行foo函数中的inner函数,但是仍要判断inner函数是否引用了foo函数中的变量,这时候需要引入预解析器处理。

预解析器如何解决闭包所带来的问题 ?

V8引入预解析器,比如当解析顶层代码的时候,遇到了一个函数,那么预解析器并不会直接跳过该函数,而是对该函数做一次快速的预解析,其主要目的有两个。
第一,是判断当前函数是不是存在一些语法上的错误,如下面这段代码:

function foo(a, b) {
{/} //语法错误
}
var a = 1
var c = 4
foo(1, 5)

第二,除了检查语法错误之外,预解析器另外的一个重要的功能就是检查函数内部是否引用了外部变量,如果引用了外部的变量,预解析器会将栈中的变量复制到堆中,在下次执行到该函数的时候,直接使用堆中的引用,这样就解决了闭包所带来的问题。

此文章为5月Day18学习笔记,内容来源于极客时间《图解 Google V8》,日拱一卒,每天进步一点点💪💪
点赞
收藏
评论区
推荐文章
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Java层逆向分析方法和技巧
本公众号分享的所有技术仅用于学习交流,请勿用于其他非法活动,如有错漏,欢迎留言指正Java层逆向分析方法和技巧一、smali汇编1.Dalvik字节码java字节码、Dalvik字节码、机器码之间的关系?在Android上,Java代码首先经过编译器编译成
Stella981 Stella981
4年前
Javascript解析机制 执行机制
HTML5学堂:在学习JavaScript过程中,我们需要了解事件的机制是怎么执行的?本文将会提到JavaScript事件机制的解析,希望对大家有帮助!javascript解析的过程主要分为两个阶段,分别是编译与执行阶段。在编译期,javascript解释器将完成对javascript代码的预处理,即将javascript代码转换为字节码。在执行
Wesley13 Wesley13
4年前
Java虚拟机
  代码编译的结果从本地机器码转换为字节码,是存储格式发展的一小步,却是编程语言发展的一大步。计算机只认识0和1,所以我们的程序需要经过编译器翻译成由0和1组成的二进制格式才能由计算机执行。经过技术的发展,将编写的程序编译成二进制本地机器码已经不是唯一的选择,越来越多的程序语言选择了与操作系统和机器指令无关、平台中立的格式作为程序编译后的存储格式。   
Stella981 Stella981
4年前
JS 苹果手机日期显示NaN问题
问题描述newDate("2019122910:30:00")在IOS下显示为NaN原因分析带的日期IOS下存在兼容问题解决方法字符串替换letdateStr"2019122910:30:00";datedateStr.repl
Stella981 Stella981
4年前
JavaScript 执行效率不行?因为你还没用 V8
作为当下使用最广泛的JavaScript引擎,V8的生态圈非常庞大,这与它革命性的设计密不可分。V8出现之前,所有JavaScript引擎用的都是解释执行的方式,这是JS执行速度过慢的主要原因;而V8引入的即时编译(JIT)双轮驱动设计,混合编译执行和解释执行两种手段,为JavaScript的执行速度带来了极大
Stella981 Stella981
4年前
JavaScript 代码是如何被 Babel 编译的
!(https://oscimg.oschina.net/oscnet/d47ca52f7cbdb3b7b5f9664f4e956e1a6cb.png)前言本文写于 2019年,如有不对之处欢迎指出。Babel对于前端开发者来说应该是很熟悉了,日常开发中基本上是离不开它的。已经9102 年了,我们已经能够熟练地使用
Wesley13 Wesley13
4年前
V8世界探险 (1)
版权声明:本文为博主原创文章,遵循CC4.0bysa版权协议,转载请附上原文出处链接和本声明。本文链接:https://blog.csdn.net/lusing/article/details/53035185V8世界探险(1)v8API概览v8是Google开发的JavaScript引擎,自推出后就对js生态产生了巨大的影响
小万哥 小万哥
2年前
如何通过Makefile优化加速编译过程提高开发效率
在软件开发中,编译是一个必不可少的过程。但是,当代码规模变得越来越大时,编译时间也会变得越来越长,这会严重影响开发效率。在这种情况下,优化Makefile可以帮助我们加速编译过程,以下是一些Makefile优化的建议使用多线程编译使用多线程编译是一种提高编
从原理聊JVM(五):JVM的编译过程和优化手段 | 京东云技术团队
一、前端编译前端编译就是将Java源码文件编译成Class文件的过程,编译过程分为4步:1准备初始化插入式注解处理器(AnnotationProcessingTool)。2解析与填充符号表将源代码的字符流转变为标记(Token)集合,构造出抽象语法树(AS
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
代码银月使
代码银月使
Lv1
此地动归念,长年悲倦游。
文章
4
粉丝
0
获赞
0