V8 什么时候开始编译和执行与事件循环堆栈相关的代码? [英] When does V8 starts compiling and executing the code in relation to the event loop stack?

查看:28
本文介绍了V8 什么时候开始编译和执行与事件循环堆栈相关的代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一直很好奇js代码是如何从头到尾执行的.

I have been curious of how js code is executed from beginning to the end.

我已阅读有关事件循环的内容,并看到了此精彩视频这里,以及了解 V8 引擎如何编译 js代码 此处.

I have read about the event loop and seen this great video, how stack frames look like here,and also read about how the V8 engine compiles js code here.

问题:

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

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

is it when the function is about to get popped out of the stack?

还是所有的函数都在它们被放入堆栈之前就被编译?

or do all functions get compiled, right before they are placed on the stack ?

因此,将其他函数放在最上面的过程实际上只是处理机器代码,如果是这样,从堆栈中弹出函数时会执行该机器代码吗?

therefore the proccess of putting other function on top is acctually only dealing with machine code, if so does the execution of that machine code occurs when popping the function from the stack ?

如果我的问题没有被理解,我相信通过这个例子会更好地理解

In case my question is not understood, i believe via this example it would be better understood

示例:

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解析,所有文件都被解析为语法错误,但没有完全解析,所以需要更少的时间.
  2. 遍历函数声明

  1. the first process that occurs is lazy parsing, where all the file is being parsed for syntax errors, but not fully parsed so it takes less time.
  2. going through the function declerations

  • v8 引擎现在是否将函数声明代码编译为机器码?或者还没有轮到他..

baz 被调用,baz 被放置在堆栈的底部,并且在它的堆栈帧中存储了 name 变量值(因为它是一个原语).

baz is called , baz is placed on bottom of the stack ,and in its stack frame the name variable value is stored (since its a primitive).

  • 什么时候 buz 被解析并转换成机器码?在将其放入堆栈之前?或者什么时候弹出?

console.log 放在 baz 之上并被执行, - 控制台显示 baz

console.log placed on top of baz and is executed, - console shows baz

  • 这是console.log js 代码编译成机器码执行的地方?

console.log 弹出堆栈.

console.logs pops of the stack.

foo 放置在 baz 之上,obj 放置在堆中(因为它是引用类型),而 name=foo 放置在 foo 的堆栈帧中.

foo is placed on top of baz, obj is placed in heap (since its a reference type), and name=foo is placed in foo`s stack frame.

console.log 在 foo 之上,并被执行,console 显示 6.

console.log goes on top of foo, and is executed , console shows 6.

推荐答案

没有事件循环堆栈"这样的东西.

There is no such thing as "the event loop stack".

一个概念是调用堆栈",这是一个术语,表示当函数相互调用时,它们形成了一个类似堆栈的当前状态.这主要是一个理论上的概念,但碰巧的是,确实有一块内存区域被称为堆栈",用于函数的局部变量,但它不是一个带有 push/pop 接口的数据结构:调用函数的行为将它的数据放在这个堆栈上,从函数返回会再次删除它,将控制权返回给调用函数.

One concept is the "call stack", which is a term for the fact that when functions call each other, they form a stack-like current state of things. This is mostly a theoretical concept, but as it happens, there is indeed an area of memory that is called "the stack" and is used for functions' local variables, but it is not a data structure with a push/pop interface: the act of calling a function places its data on this stack, and returning from the function removes it again, returning control to the calling function.

这回答了您函数的一部分:开始执行函数实际上与将此函数放在调用堆栈上完全相同.这是对同一事物的两种描述.

This answers part of your function: starting to execute a function is literally exactly the same as having this function placed on the call stack. Those are two descriptions for the same thing.

另一个概念是事件队列.您可以将其视为等待执行的函数队列;每当没有其他函数正在执行时,就会调用此队列中的下一个函数.将一个函数放入队列不需要它被解析或编译.在您的示例代码段中,根本没有使用事件队列.

Another concept is the event queue. You can think of it as a queue of functions waiting to be executed; whenever no other function is executing, the next function from this queue is called. Putting a function into the queue does not require it to have been parsed or compiled. In your example snippet, the event queue is not used at all.

编译函数真的与这一切无关.当一个函数被调用时(被另一个函数或事件循环调用),它必须以某种形式可执行——但取决于你的 JavaScript 引擎,它可以在没有任何编译的情况下被解释,或者它可以被编译为字节码,或者它可以被编译成机器码,或者引擎可以利用这个机会从一个切换到另一个.

Compiling functions is really unrelated to all this. When a function is called (by another function, or by the event loop), it has to be executable in some form -- but depending on your JavaScript engine, it could get interpreted without any compilation, or it could get compiled to bytecode, or it could get compiled to machine code, or the engine could use this opportunity to switch from one to the other.

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

Since you asked about V8 specifically: in current versions, when V8 sees a function definition like function f() { ... }, it doesn'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's bytecode like the earlier calls did. Note that these implementation details can and will change over time.

还有一点需要澄清:

在它的堆栈帧中存储了名称变量值(因为它是一个原语).

in its stack frame the name variable value is stored (since its a primitive).

不完全是.变量本身存储在堆栈帧中,但仅作为参考.它是否指代原始值并不重要;字符串和对象都在堆上分配.函数返回时局部变量会被销毁,栈帧被拆除;堆上的相应对象或字符串将(最终,在某个不确定的时间)被垃圾收集器清除.

Not quite. The variable itself is stored in the stack frame, but only as a reference. Whether it refers to a primitive value or not doesn't matter; strings and objects are both allocated on the heap. The local variable will be destroyed when the function returns and its stack frame is torn down; the respective object or string on the heap will (eventually, at some indeterminate time) be cleaned up by the garbage collector.

这篇关于V8 什么时候开始编译和执行与事件循环堆栈相关的代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆