哪个事件循环阶段执行普通 JavaScript 代码
Which Event Loop Phase Executes Ordinady JavaScript Code
我是 node.js 的新手,对事件循环的理解有点困惑。据我所知 https://github.com/nodejs/node/blob/master/doc/topics/event-loop-timers-and-nexttick.md,事件循环阶段仅处理 setTimeout、setInterval、setImmediate、process.nextTick、promises 和一些 I/O 回调。
我的问题是,如果我有以下代码:
for (var i = 0; i < 100000000; i++)
;
上述代码将在哪个阶段执行?
常规 JavaScript 代码,如示例中的 for
循环,在队列被清除之前执行。节点将做的第一件事是 运行 您的代码,并且只会调用回调、超时结果、I/O 结果等 在 您的代码完成后。
例如,您可以尝试以下代码:
fs.open('filename', 'r', () => {
console.log('File opened.');
});
for (var i = 0; i < 100000000; i++);
console.log('Loop complete.');
无论你的循环变量有多大或多小,'Loop complete'总是出现在'File opened'之前。这是因为只有一个线程,在循环代码完成之前,节点无法 运行 您提供给 fs.open 函数的回调。
请记住,没有 "main" 节点不断返回的线程。大多数 long-running 节点程序将 运行 快速完成 main.js 中的代码,后续代码将全部来自回调。初始执行的目的是定义这些回调发生的方式和时间。
在节点事件循环文档(https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick)中,给出如下代码作为示例:
const fs = require('fs');
function someAsyncOperation(callback) {
// Assume this takes 95ms to complete
fs.readFile('/path/to/file', callback);
}
const timeoutScheduled = Date.now();
setTimeout(() => {
const delay = Date.now() - timeoutScheduled;
console.log(`${delay}ms have passed since I was scheduled`);
}, 100);
// do someAsyncOperation which takes 95 ms to complete
someAsyncOperation(() => {
const startCallback = Date.now();
// 10ms loop
while (Date.now() - startCallback < 10) {
// do nothing
}
});
循环一直按阶段扫描,fs.readFile()
结束后,轮询队列为空,因此会添加回调并立即执行。在执行计时器之前,回调持有一个阻塞的 10ms 循环。这就是延迟将显示的原因:
105ms have passed since I was scheduled
而不是您可能期望的 100 毫秒。
您的大部分代码将存在于回调中,因此将在 poll 阶段执行。如果不是,就像在您的示例中一样,它将在进入任何阶段之前执行,因为它将阻塞事件循环。
需要注意的是 setImmediate
安排的回调将进入 check 阶段,然后在下一个循环中恢复轮询阶段。
我是 node.js 的新手,对事件循环的理解有点困惑。据我所知 https://github.com/nodejs/node/blob/master/doc/topics/event-loop-timers-and-nexttick.md,事件循环阶段仅处理 setTimeout、setInterval、setImmediate、process.nextTick、promises 和一些 I/O 回调。
我的问题是,如果我有以下代码:
for (var i = 0; i < 100000000; i++) ;
上述代码将在哪个阶段执行?
常规 JavaScript 代码,如示例中的 for
循环,在队列被清除之前执行。节点将做的第一件事是 运行 您的代码,并且只会调用回调、超时结果、I/O 结果等 在 您的代码完成后。
例如,您可以尝试以下代码:
fs.open('filename', 'r', () => {
console.log('File opened.');
});
for (var i = 0; i < 100000000; i++);
console.log('Loop complete.');
无论你的循环变量有多大或多小,'Loop complete'总是出现在'File opened'之前。这是因为只有一个线程,在循环代码完成之前,节点无法 运行 您提供给 fs.open 函数的回调。
请记住,没有 "main" 节点不断返回的线程。大多数 long-running 节点程序将 运行 快速完成 main.js 中的代码,后续代码将全部来自回调。初始执行的目的是定义这些回调发生的方式和时间。
在节点事件循环文档(https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick)中,给出如下代码作为示例:
const fs = require('fs');
function someAsyncOperation(callback) {
// Assume this takes 95ms to complete
fs.readFile('/path/to/file', callback);
}
const timeoutScheduled = Date.now();
setTimeout(() => {
const delay = Date.now() - timeoutScheduled;
console.log(`${delay}ms have passed since I was scheduled`);
}, 100);
// do someAsyncOperation which takes 95 ms to complete
someAsyncOperation(() => {
const startCallback = Date.now();
// 10ms loop
while (Date.now() - startCallback < 10) {
// do nothing
}
});
循环一直按阶段扫描,fs.readFile()
结束后,轮询队列为空,因此会添加回调并立即执行。在执行计时器之前,回调持有一个阻塞的 10ms 循环。这就是延迟将显示的原因:
105ms have passed since I was scheduled
而不是您可能期望的 100 毫秒。
您的大部分代码将存在于回调中,因此将在 poll 阶段执行。如果不是,就像在您的示例中一样,它将在进入任何阶段之前执行,因为它将阻塞事件循环。
需要注意的是 setImmediate
安排的回调将进入 check 阶段,然后在下一个循环中恢复轮询阶段。