Node.js nextTick vs setImmediate,直观解释

Node.js nextTick vs setImmediate,直观解释,node.js,Node.js,我很困惑nextTick和setImmediate之间的区别。我已经在互联网上阅读了所有关于它们的文档,但我仍然不明白它们是如何工作的 示例: function log(n) { console.log(n); } setImmediate setImmediate(function() { setImmediate(function() { log(1); setImmediate(function() { log(2); }); setImmediate(fun

我很困惑nextTick和setImmediate之间的区别。我已经在互联网上阅读了所有关于它们的文档,但我仍然不明白它们是如何工作的

示例:

function log(n) { console.log(n); }
setImmediate

setImmediate(function() {
  setImmediate(function() {
    log(1);
    setImmediate(function() { log(2); });
    setImmediate(function() { log(3); });
  });
  setImmediate(function() {
    log(4);
    setImmediate(function() { log(5); });
    setImmediate(function() { log(6); });
  });
});

//1 2 3 4 5 6
setImmediate(function A() {
  setImmediate(function B() {
    log(1);
    setImmediate(function D() { log(2); });
    setImmediate(function E() { log(3); });
  });
  setImmediate(function C() {
    log(4);
    setImmediate(function F() { log(5); });
    setImmediate(function G() { log(6); });
  });
});

setTimeout(function timeout() {
  console.log('TIMEOUT FIRED');
}, 0)

// 'TIMEOUT FIRED' 1 4 2 3 5 6
// OR
// 1 'TIMEOUT FIRED' 4 2 3 5 6
nextTick

process.nextTick(function() {
  process.nextTick(function() {
    log(1);
    process.nextTick(function() { log(2); });
    process.nextTick(function() { log(3); });
  });
  process.nextTick(function() {
    log(4);
    process.nextTick(function() { log(5); });
    process.nextTick(function() { log(6); });
  });
});

//1 4 2 3 5 6
process.nextTick(function A() {
  process.nextTick(function B() {
    log(1);
    process.nextTick(function D() { log(2); });
    process.nextTick(function E() { log(3); });
  });
  process.nextTick(function C() {
    log(4);
    process.nextTick(function F() { log(5); });
    process.nextTick(function G() { log(6); });
  });
});

setTimeout(function timeout() {
  console.log('TIMEOUT FIRED');
}, 0)

// 1 4 2 3 5 6 'TIMEOUT FIRED'
为什么会有这些结果?请用直观的或易于理解的解释进行解释。即使是节点核心开发人员也不同意人们应该如何理解nextTick和setImmediate

资料来源:


    • 我无法为
      setImmediate
      复制您的结果。它应该与nextTick(在我的测试中)相同,因为在这种情况下,它们做的事情几乎相同。唯一合理的解释是,
      setImmediate
      在某种程度上是同步的,但它不是


      根据唯一的实际区别,多个
      nextTick
      可能在一次循环迭代中触发(取决于
      maxTickDepth
      ),而
      setImmediate
      每次迭代触发一次。

      考虑以下两个示例:

      setImmediate

      setImmediate(function() {
        setImmediate(function() {
          log(1);
          setImmediate(function() { log(2); });
          setImmediate(function() { log(3); });
        });
        setImmediate(function() {
          log(4);
          setImmediate(function() { log(5); });
          setImmediate(function() { log(6); });
        });
      });
      
      //1 2 3 4 5 6
      
      setImmediate(function A() {
        setImmediate(function B() {
          log(1);
          setImmediate(function D() { log(2); });
          setImmediate(function E() { log(3); });
        });
        setImmediate(function C() {
          log(4);
          setImmediate(function F() { log(5); });
          setImmediate(function G() { log(6); });
        });
      });
      
      setTimeout(function timeout() {
        console.log('TIMEOUT FIRED');
      }, 0)
      
      // 'TIMEOUT FIRED' 1 4 2 3 5 6
      // OR
      // 1 'TIMEOUT FIRED' 4 2 3 5 6
      
      nextTick

      process.nextTick(function() {
        process.nextTick(function() {
          log(1);
          process.nextTick(function() { log(2); });
          process.nextTick(function() { log(3); });
        });
        process.nextTick(function() {
          log(4);
          process.nextTick(function() { log(5); });
          process.nextTick(function() { log(6); });
        });
      });
      
      //1 4 2 3 5 6
      
      process.nextTick(function A() {
        process.nextTick(function B() {
          log(1);
          process.nextTick(function D() { log(2); });
          process.nextTick(function E() { log(3); });
        });
        process.nextTick(function C() {
          log(4);
          process.nextTick(function F() { log(5); });
          process.nextTick(function G() { log(6); });
        });
      });
      
      setTimeout(function timeout() {
        console.log('TIMEOUT FIRED');
      }, 0)
      
      // 1 4 2 3 5 6 'TIMEOUT FIRED'
      
      setImmediate回调从事件循环中触发,每次迭代按其排队顺序触发一次。因此,在事件循环的第一次迭代中,将触发回调。然后在事件循环的第二次迭代中,启动回调B,然后在事件循环的第三次迭代中启动回调C,等等。这可以防止事件循环被阻塞,并允许在平均时间内调用其他I/O或计时器回调(与在第一次或第二次循环迭代中启动的0ms超时的情况相同)


      但是,nextTick回调总是在当前代码执行完毕之后以及返回事件循环之前立即触发。在nextTick示例中,我们在返回事件循环之前执行所有nextTick回调。由于setTimeout的回调将从事件循环中调用,因此在完成每个nextTick回调之前,不会输出文本“TIMEOUT FIRED”。

      根据Node.js,这两个函数的doc名称是

      setImmediate()(最佳推荐)

      这是事件队列中的第一个火灾


      process.nextTick()

      它马上就着火了,它有点像是在当前文件的末尾多写一条语句


      如果我们有这个密码

      setTimeout(function(){
        console.log('Hello world 5'); // It's waiting like a normal person at a queue
      }, 0);
      
      setImmediate(function(){
        console.log('Hello world 4'); 
        // It's like get to last and be take care of first 
        // but always after of .nextTick and before of setInterval(, 0)
      });
      
      process.nextTick(function(){
         console.log('Hello world 3'); // It's like be at the bottom at this file
      });
      
      console.log('Hello world 1');
      console.log('Hello world 2');
      
      根据您的要求提供视觉解释:

      在处理process.nextTick()之前必须发出和事件的情况下,使用process.nextTick()的情况:

      const EventEmitter = require('events');
      const util = require('util');
      
      function MyEmitter() {
        EventEmitter.call(this);
      
        // use nextTick to emit the event once a handler is assigned
        process.nextTick(function () {
          this.emit('event');
        }.bind(this));
      }
      util.inherits(MyEmitter, EventEmitter);
      
      const myEmitter = new MyEmitter();
      myEmitter.on('event', function() {
        console.log('an event occurred!');
      });
      
      请看这段视频,其中为我们提供了有关运行时事件循环的详细解释,并查看此在线事件循环调试器

      资料来源:

      我认为上面所有的答案都过时了,因为我在当前版本的nodejs中不断得到不同的答案,而且很容易推理

      var log=console.log
      log(process.version)
      
      var makeAsyncCall
      if(false)
          makeAsyncCall=setImmediate
      else
          makeAsyncCall=process.nextTick;
      
      makeAsyncCall(function A () {
          makeAsyncCall(function B() {
              log(1);
              makeAsyncCall(function C() { log(2); });
              makeAsyncCall(function D() { log(3); });
          });
          makeAsyncCall(function E() {
              log(4);
              makeAsyncCall(function F() { log(5); });
              makeAsyncCall(function G() { log(6); });
          });
      });
      //1
      //4
      //2
      //3
      //5
      //6
      //in both case
      
      读后 让我们使用start from
      setImmediate
      我们应该跟踪
      检查队列,因为它是
      setImmediate
      回调所在的位置

      第一次迭代

      A
      被推送到
      检查队列

      检查队列:[A]

      第二次迭代

      A
      队列中拉出执行

      在执行过程中,它将
      B
      E
      放入
      队列
      ,然后,
      A
      完成并开始下一次迭代

      检查队列:[B,E]

      第三次迭代

      拉出
      B
      并推
      C
      D

      检查队列:[E、C、D]

      第四次迭代

      拉出
      E
      并推
      F
      G

      检查队列:[C、D、F、G]

      最后

      按顺序执行队列中的回调

      对于
      nextTick
      情况,队列的工作方式完全相同,这就是它产生相同结果的原因

      不同之处在于:

      将在当前操作后处理nextTickQueue 完成,与事件循环的当前阶段无关

      需要说明的是,事件循环维护多个队列,
      check queue
      只是其中之一,节点将根据一些规则决定使用哪个队列


      然而,对于
      process.nextTick
      ,它有点绕过所有规则,并立即执行下面
      nextTick
      中的回调,从而使您更清晰

    • 一旦当前轮询阶段完成,将执行一个脚本
    • 这是一个定时器模块函数,定时器函数是全局函数,您可以调用它们,而无需
      require
    • 它可以通过clearImmediate()清除
    • 在setTimeout()和setInterval()之前的I/O事件回调之后,设置回调的“立即”执行
    • 它是NodeJS的一个进程全局对象函数
    • 在事件循环继续之前,将解析传递给process.nextTick()的所有回调
    • 允许用户处理错误
    • 帮助在事件循环继续之前重试请求 简单的代码片段。
      很好,最后一段是理解主要区别的关键。您的nextTick示例有不同的输出:
      TIMEOUT FIRED 1 4 2 3 5 6
      您正在运行哪个版本的节点?在节点0.10.x上,在点击事件循环之前,您应该始终运行nextTick回调。我希望他们选择不同的名称。现在“nextTick”比setImmediate更直接。@struglingcoder因为当A执行时,它将B和C设置为下一个计划。当B执行时,它将D和E设置为下一个调度,但C已经被安排在B之后。记住,调度或注册回调的时间与实际触发回调的时间是有区别的。好问题。这是一个很好的方法