【问题标题】:Which Event Loop Phase Executes Ordinady JavaScript Code哪个事件循环阶段执行普通 JavaScript 代码
【发布时间】:2017-06-01 14:48:53
【问题描述】:

我是 node.js 的新手,对理解事件循环有点困惑。据我从https://github.com/nodejs/node/blob/master/doc/topics/event-loop-timers-and-nexttick.md 了解到,事件循环阶段仅处理 setTimeout、setInterval、setImmediate、process.nextTick、promise 和一些 I/O 回调。

我的问题是,如果我有以下代码:

for (var i = 0; i

上面的代码会在哪个阶段执行?

【问题讨论】:

  • 除非我遗漏了什么,否则我不会期望 for 循环被视为由事件循环处理的“事件”。
  • I/O callbacks: executes almost all callbacks...。在节点中,处理请求的 HTTP 服务器是 I/O。
  • 那么,代码将在哪里执行。它是通过调用堆栈执行的吗?
  • 事件循环是一个队列。如果我没记错的话,这些阶段是不同的优先级队列。
  • 如果不被事件循环处理,你会认为代码本身没有阻塞事件循环吗?

标签: node.js event-loop


【解决方案1】:

常规 JavaScript 代码(如您示例中的 for 循环)在队列被清除之前执行。节点要做的第一件事是运行您的代码,并且只会在您的代码完成后调用回调、超时结果、I/O 结果等。

例如,您可以尝试以下代码:

fs.open('filename', 'r', () => {
  console.log('File opened.');
});

for (var i = 0; i < 100000000; i++);

console.log('Loop complete.');

无论您的循环变量有多大或多小,“循环完成”总是会出现在“文件打开”之前。这是因为只有一个线程,在循环代码完成之前,节点无法运行您提供给 fs.open 函数的回调。

请记住,节点不会一直返回到“主”线程。大多数长时间运行的节点程序将很快运行 main.js 中的代码,后续代码都将来自回调。初始执​​行的目的是定义这些回调发生的方式和时间。

【讨论】:

    【解决方案2】:

    在节点事件循环文档(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()完成后,轮询队列为空,因此将添加其回调并立即执行。在执行计时器之前,回调会保留一个阻塞 10 毫秒的循环。这就是延迟将显示的原因: 105ms have passed since I was scheduled 而不是您可能期望的 100 毫秒。

    您的大部分代码将存在于回调中,因此将在 poll 阶段执行。如果不是,就像在您的示例中一样,它将在进入任何阶段之前执行,因为它会阻塞事件循环。

    需要注意的是由setImmediate 安排的回调将进入 check 阶段,然后在下一个循环中恢复轮询阶段。

    【讨论】:

      猜你喜欢
      • 2014-10-10
      • 2021-10-07
      • 1970-01-01
      • 2012-03-31
      • 2023-03-29
      • 1970-01-01
      • 2018-03-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多