哪个事件循环阶段执行普通 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 阶段,然后在下一个循环中恢复轮询阶段。