第二关.JavaScript执行机制

114 阅读4分钟

引言:通过第一关,我们知道JavaScript源代码在经过JS引擎的解析、解释等一系列操作后,源代码被转化成了字节码,那么这些字节码最终是如何被执行的呢?

目的:那么接下来让我们一起去了解字节码的整个执行过程吧。

1. 导读

在讲JavaScript源代码如何执行之前,我们先来了解一下解释性语言和编译型语言的概念。

  • 解释型语言:程序不需要提前编译,程序在运行时才翻译成机器语言,每执行一次都要翻译一次。
  • 编译型语言:程序提前使用编译器一次性将所有源代码编译为一个可执行程序,一次编译可重复执行。

JavaScript是一种解释性编程语言,因此其是一边解释一边执行的。

2.执行前逻辑

这里的执行机制,以Google公司的V8引擎(2017版)为例。流程如下:

image.png

  1. 首先,编写好的JavaScript源代码被加载到V8引擎中;
  2. 然后,V8引擎的解析器(Parser)将代码解析为抽象语法树(Abstract Syntax Tree,简称AST)和执行上下文;
  3. 最后,V8引擎的解释器(Ignition)将AST解释为字节码。

2.1 Parser再探究

Parser解析的时候并不会进行全量解析(全部解析1.耗时间;2.解析后的字节码需放入内存耗内存),而是有延迟解析的策略,也就是一种按需解析的方案。首先Parpaser会解析出所需的最少限度的内容,比如内部有未调用的函数,则解析出函数声明,只有当函数被调用时才对该函数进行完整的解析。

2.2 Ignition再探究

Ignition关注的是减少 V8 的内存开销,会进行执行前的优化工作。它会将AST进行分析将多次调用的函数标记为热点函数并交由TurboFan进行编译生成优化后的机器码执行,而单次调用的函数则会被生成字节码再做执行。

3. 执行时逻辑

当AST解释完成的时候,V8引擎的高性能解释器就会对字节码进行解释执行操作,流程如下:

image.png

  1. 首先,将解析器生成的对应执行上下文压入到执行上下文栈中;
  2. 然后,加载字节码,并将其转化成成机器码;
  3. 最后,进行代码的执行。

下面以一个简单的例子,详细讲述一下执行阶段流程中执行上下文的出入栈流程。

function a() {
  console.log('a');
  b();
}
function b() {
  console.log('b');
}
a()
  1. 在执行代码之前,会将全局代码解析时所生成的Global Execute Context压入到栈中,并将全局代码放入call stack中执行;
  2. 执行a()函数之前,此时会对a()函数进行解析(延迟解析策略),生成a Execute Context,并将其压入到栈中,同时将a函数代码放入call stack中执行;
  3. 执行b()函数,此时会对b()函数进行解析(延迟解析策略),生成b Execute Context,并将其压入到栈中,同时将b函数代码放入call stack中执行;
  4. b()函数执行完毕,b Execute Contex从调用栈退出;
  5. a()函数执行完毕,a Execute Contex从调用栈退出;
  6. 全部代码执行完毕,Global Execute Contex从调用栈退出,结束执行;

image.png

4. 异步任务执行逻辑

我们知道JavaScript是单线程的,即同一时间调用栈中只能有一段代码被执行。那么按理论分析的话,当程序中有异步任务时,是不是就会出现需要等待异步任务结束,从而导致阻塞的情况呢?

那么实际上真如上述分析一样吗? 下面以一个小例子实际验证一下:

const a = 1;
setTimeout(()=> {
    console.log('timeout');
}, 1000)
console.log(a)

按照理论上的分析,此时的输出结果应该依次是: timeout 1,并且timeout需要在1s之后才会输出; 但实际上的输出结果是: 1 timeout,并且整个程序没有出现阻塞的现象。

4.1 callback queue

那么V8引擎,是如何避免异步任务的阻塞呢? 不知道大家还记不记得在JS引擎和运行时这一关中,我们讲到了运行时,其中包含一个callback queue。当程序中的异步任执行后并不会一直等待其返回结果,而是会将这个事件挂起,继续执行栈中的其他任务,当一个异步任务返回结果后,V8引擎会将这个事件加入到这个callback queue。当栈中任务执行完成之后,才会查询该队列中的回调函数,并将其放入到栈中执行,从而避免异步任务的阻塞。

image.png

5. 参考资料

  1. baijiahao.baidu.com/s?id=173728…
  2. v8.dev/blog/scanne…
  3. v8.dev/blog/igniti…
  4. www.51cto.com/article/628…
  5. blog.csdn.net/qq_41887214…