我很好奇从头到尾如何执行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();
进行功能描述
baz被称为,baz放置在堆栈的底部,并且在其堆栈框架中存储了名称变量值(因为它是基元)。
console.log放在baz顶部并被执行,-控制台显示baz
console.logs弹出堆栈。
foo被放置在baz的顶部,obj被放置在堆中(由于其是引用类型),而name=foo
被放置在foo的堆栈框架中。
console.log放在foo之上,并被执行,控制台显示6。
name=baz
局部变量弹出答案 0 :(得分:2)
没有“事件循环栈”之类的东西。
一个概念是“调用堆栈”,这是一个事实,即函数彼此调用时,它们会形成类似堆栈的当前状态。这主要是一个理论概念,但碰巧的是,确实存在一个内存区域,称为“堆栈”,用于函数的局部变量,但它不是具有push / pop接口的数据结构:调用函数的行为将其数据放在此堆栈上,然后从函数返回将其删除,从而将控制权返回给调用函数。
这回答了部分函数:开始执行一个函数与将这个函数放在调用堆栈上完全相同。这是对同一件事的两种描述。
另一个概念是事件队列。您可以将其视为等待执行的功能队列;只要没有其他函数在执行,就会从该队列中调用下一个函数。将函数放入队列并不需要对其进行解析或编译。在您的示例代码段中,根本不使用事件队列。
编译功能实际上与这一切无关。调用一个函数(通过另一个函数或事件循环)时,它必须以某种形式执行-但取决于您的JavaScript引擎,可以不进行任何编译就解释它,也可以将其编译为字节码,或者可以将其编译为机器代码,或者引擎可以利用这一机会从一个切换到另一个。
由于您是专门询问V8的:在当前版本中,当V8看到类似function f() { ... }
的函数定义时,它什么都不做(除了少数情况下,V8猜测该函数将被执行)很快,在这种情况下,它将立即为其创建字节码)。如果该函数作为回调排队,则仍然不会进行解析或编译。首次调用函数时,V8会为其创建字节码。当再次调用该函数时,字节码已经存在,因此不需要其他工作。当一个函数运行得足够热时,V8最终决定通常在后台线程上为其编译优化的机器代码。对它的其他调用使V8有机会检查后台线程是否已经完成了生成机器代码的过程。如果是这样,则下一次调用将使用优化的代码,而不是像先前的调用那样解释函数的字节码。请注意,这些实施细节可能会并且会随着时间而改变。
还有一个注释需要澄清:
在其堆栈框架中存储了名称变量值(因为它是基元)。
不完全是。 变量本身存储在堆栈框架中,但仅供参考。是否引用原始值都无关紧要;字符串和对象都分配在堆上。当函数返回并且其堆栈框架被破坏时,局部变量将被销毁。堆中的相应对象或字符串(最终,将在不确定的时间)被垃圾收集器清除。