如果代码较大且调用堆栈不为空,事件循环如何在 2 秒内准确执行代码?

how event loop exactly executes code in 2 seconds if the code is larger and call stack is not empty?

很多解释都说调用栈是空的,但我不明白,如果我们设置一个 2 秒的计时器并以异步方式执行代码,如果我有一个代码 运行 10秒的时间,call-stack不为空,回调队列中的回调函数会等待11秒执行吗?

...will the callback function in the callback queue waits for 11 sec to be executed?

不一定是11秒,不是; 10 秒同步代码完成后不久,它将 运行。定时器的长度是否比同步代码持续时间短无关紧要。 this page 中有关 Node.js 事件循环如何工作的更多详细信息。

例如,使用此代码:

function elapsed(start) {
    const elapsed = Date.now() - start;
    return `${(elapsed / 1000).toFixed(4)}s`;
}
const startTimer = Date.now();
console.log(`Starting timer`);
setTimeout(() => {
    console.log(`Timer fired after ${elapsed(startTimer)}`);
}, 2000);
const finish = Date.now() + 10000;
const startBusyWait = Date.now();
console.log(`Starting to wait`);
while (Date.now() < finish) {
    // Busy-wait -- DON'T DO THIS
}
console.log(`Done busy-waiting after ${elapsed(startBusyWait)}`);

您会看到如下内容:

Starting timer
Starting to wait
Done busy-waiting after 10.0000s
Timer fired after 10.0050s

是的。想象一下这段代码:

setTimeout(function() {
  console.log('hi');
}, 0);

let i = 0;

while (i <= 1e9) {
  i++;
}

这里发生了什么?

setTimeout 中的代码被“推迟”到“当前调用堆栈为空后”0 毫秒后 运行。

但是当前脚本必须完成它的循环。因此,如果您 运行 这段代码,它将等到 i 计数到 1e9,然后再将“hi”记录到控制台。

jsfiddle code