V8何时开始编译和执行与事件循环堆栈相关的代码?

时间:2018-12-08 20:02:51

标签: javascript v8

我很好奇从头到尾如何执行js代码。

我已经阅读了有关事件循环的内容,并看到了这个great video, 堆栈框架看起来像here的样子,并了解V8引擎如何编译js代码here

问题:

V8何时开始编译和执行与事件循环堆栈相关的代码?

是该函数即将从堆栈中弹出吗?

还是在将所有函数放入堆栈之前就对它们进行编译?

因此,将其他功能放在首位的过程实际上只是处理机器代码,如果是这样,当从堆栈中弹出该功能时是否会执行该机器代码?

如果我的问题不明白,我相信通过此示例会更好地理解

示例:

function foo() {
    var name=`foo`;
    var obj = {
        number: 6
    }
    console.log(obj.number);
}

function baz() {
    var name = `baz`;
    console.log(a);
    foo();
}

baz();
  1. 发生的第一个过程是lazy parsing,在该过程中,将对所有文件进行语法错误分析,但未完全分析,因此所需的时间更少。
  2. 进行功能描述

    • v8引擎现在将函数声明代码编译为 机器码?还是该轮到他了。
  3. baz被称为,baz放置在堆栈的底部,并且在其堆栈框架中存储了名称变量值(因为它是基元)。

    • 何时准确解析buz并将其转换为机器代码?在将其放置在堆栈上之前?或何时弹出?
  4. console.log放在baz顶部并被执行,-控制台显示baz

    • 这是 将console.log js代码编译为机器代码并执行的地方?
  5. console.logs弹出堆栈。

  6. foo被放置在baz的顶部,obj被放置在堆中(由于其是引用类型),而name=foo被放置在foo的堆栈框架中。

  7. console.log放在foo之上,并被执行,控制台显示6。

  8. console.log弹出。
  9. 弹出
  10. foo及其局部变量值。
  11. baz及其name=baz局部变量弹出

1 个答案:

答案 0 :(得分:2)

没有“事件循环栈”之类的东西。

一个概念是“调用堆栈”,这是一个事实,即函数彼此调用时,它们会形成类似堆栈的当前状态。这主要是一个理论概念,但碰巧的是,确实存在一个内存区域,称为“堆栈”,用于函数的局部变量,但它不是具有push / pop接口的数据结构:调用函数的行为将其数据放在此堆栈上,然后从函数返回将其删除,从而将控制权返回给调用函数。

这回答了部分函数:开始执行一个函数与将这个函数放在调用堆栈上完全相同。这是对同一件事的两种描述。

另一个概念是事件队列。您可以将其视为等待执行的功能队列;只要没有其他函数在执行,就会从该队列中调用下一个函数。将函数放入队列并不需要对其进行解析或编译。在您的示例代码段中,根本不使用事件队列。

编译功能实际上与这一切无关。调用一个函数(通过另一个函数或事件循环)时,它必须以某种形式执行-但取决于您的JavaScript引擎,可以不进行任何编译就解释它,也可以将其编译为字节码,或者可以将其编译为机器代码,或者引擎可以利用这一机会从一个切换到另一个。

由于您是专门询问V8的:在当前版本中,当V8看到类似function f() { ... }的函数定义时,它什么都不做(除了少数情况下,V8猜测该函数将被执行)很快,在这种情况下,它将立即为其创建字节码)。如果该函数作为回调排队,则仍然不会进行解析或编译。首次调用函数时,V8会为其创建字节码。当再次调用该函数时,字节码已经存在,因此不需要其他工作。当一个函数运行得足够热时,V8最终决定通常在后台线程上为其编译优化的机器代码。对它的其他调用使V8有机会检查后台线程是否已经完成了生成机器代码的过程。如果是这样,则下一次调用将使用优化的代码,而不是像先前的调用那样解释函数的字节码。请注意,这些实施细节可能会并且会随着时间而改变。

还有一个注释需要澄清:

  

在其堆栈框架中存储了名称变量值(因为它是基元)。

不完全是。 变量本身存储在堆栈框架中,但仅供参考。是否引用原始值都无关紧要;字符串和对象都分配在堆上。当函数返回并且其堆栈框架被破坏时,局部变量将被销毁。堆中的相应对象或字符串(最终,将在不确定的时间)被垃圾收集器清除。