我一直很好奇从开始到结束执行js代码 .
我已经阅读了关于事件循环并看到了这个great video,堆栈帧看起来如何here,还读到了V8引擎如何编译js代码here .
题 :
When does V8 starts compiling and executing the code in relation to the event loop stack ?
当函数即将弹出堆栈时是什么时候?
或者在将它们放入堆栈之前编译所有函数?
因此,将其他功能放在最上面的过程实际上只是处理机器代码,如果是这样,当从堆栈弹出函数时会发生该机器代码的执行?
如果我的问题没有被理解,我相信通过这个例子可以更好地理解
示例:
function foo() {
var name=`foo`;
var obj = {
number: 6
}
console.log(obj.number);
}
function baz() {
var name = `baz`;
console.log(a);
foo();
}
baz();
-
发生的第一个进程是lazy parsing,其中所有文件都被解析为语法错误,但未完全解析,因此花费的时间更少 .
-
通过功能解决
-
v8引擎现在是否将函数声明代码编译为机器代码?还是轮到他了......
调用
-
baz,将baz放在堆栈的底部,并在其堆栈帧中存储名称变量值(因为它是一个原语) .
-
什么时候buz被解析并转换为机器码?在它放在堆栈之前?还是当它弹出来的时候?
-
console.log放在baz之上并执行, - 控制台显示
baz
-
这是将console.log js代码编译为机器代码并执行的地方吗?
-
console.logs堆栈的弹出窗口 .
-
foo放在baz之上,obj放在堆中(因为它是引用类型),
name=foo
放在foo的堆栈框架中 . -
console.log在foo之上,并且执行,控制台显示6 .
-
console.log弹出 .
-
foo弹出,连同其局部变量值 .
-
baz随着
name=baz
局部变量弹出
1 回答
没有“事件循环堆栈”之类的东西 .
一个概念是“调用堆栈”,它是一个术语,当函数相互调用时,它们形成类似堆栈的当前状态 . 这主要是一个理论概念,但实际上,存在一个称为“堆栈”的内存区域,用于函数的局部变量,但它不是具有推/弹界面的数据结构:调用函数的行为将其数据放在此堆栈上,并从函数返回将其再次删除,将控制权返回给调用函数 .
这回答了你的部分功能:开始执行一个函数与把这个函数放在调用堆栈上完全一样 . 这是同一件事的两个描述 .
另一个概念是事件队列 . 您可以将其视为等待执行的函数队列;只要没有其他函数正在执行,就会调用此队列中的下一个函数 . 将函数放入队列不需要对其进行解析或编译 . 在示例代码段中,根本不使用事件队列 .
编译功能与所有这些无关 . 当一个函数被调用(通过另一个函数,或者通过事件循环)时,它必须以某种形式执行 - 但是根据你的JavaScript引擎,它可以在没有任何编译的情况下被解释,或者它可以被编译为字节码,或者它可以编译成机器代码,或者引擎可以利用这个机会从一个切换到另一个 .
因为你特别询问了V8:在当前版本中,当V8看到像
function f() { ... }
这样的函数定义时,它不会像之前的调用那样't do anything anything yet (except for a few cases where V8 guesses that the function will be executed soon, in which case it creates bytecode for it immediately). If the function gets queued as a callback, still no parsing or compilation happens. When a function is called for the first time, V8 creates bytecode for it. When the function is called again, the bytecode exists already, so no additional work is required. When a function runs hot enough, V8 eventually decides to compile optimized machine code for it, usually on a background thread. Additional calls to it are opportunities for V8 to check whether the background thread is done producing machine code already; if so, then the next call will use that optimized code instead of interpreting the function'字节码 . 请注意,这些实现细节可能会随着时间而变化 .还有一点需要澄清:
不完全的 . 变量本身存储在堆栈帧中,但仅作为参考 . 它是否指原始值无关紧要;字符串和对象都在堆上分配 . 当函数返回并且其堆栈帧被拆除时,局部变量将被销毁;堆上的相应对象或字符串将(最终在某些不确定的时间)由垃圾收集器清理 .