nextTick vs setImmediate,直观解释

Gab*_*mas 87 node.js

我对nextTick和setImmediate之间的差异感到非常困惑.我已经在互联网上阅读了有关它们的所有文档,但我仍然不明白它们是如何工作的.

例子:

function log(n) { console.log(n); }
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

为什么这些结果?请用视觉或非常容易理解的方式解释.甚至节点核心开发人员也不同意人们应该如何理解nextTick和setImmediate.

资料来源:

Dav*_*any 102

考虑以下两个例子:

setImmediate

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
Run Code Online (Sandbox Code Playgroud)

nextTick

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'
Run Code Online (Sandbox Code Playgroud)

setImmediate回调是在事件循环中触发的,每次迭代按照它们排队的顺序触发一次.因此,在事件循环的第一次迭代中,将触发回调A. 然后在事件循环的第二次迭代中,触发回调B,然后在事件循环的第三次迭代中触发回调C等.这可以防止事件循环被阻塞并允许其他I/O或计时器回调在平均时间内调用(就像0ms超时的情况一样,在第一次或第二次循环迭代时触发).

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

  • 我希望他们会选择一个不同的名字.现在"nextTick"比setImmediate更直接. (23认同)
  • 完美,最后一段是理解主要区别的关键. (8认同)

gsa*_*edo 23

根据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');
Run Code Online (Sandbox Code Playgroud)

根据您的要求进行直观说明:

在此输入图像描述

使用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!');
});
Run Code Online (Sandbox Code Playgroud)

看看这个视频菲利普罗伯茨给我们一个关于运行时事件循环的一个很好的解释,看看这个在线eventloop调试器实时测试事件循环如何工作

资料来源:https: //github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md#processnexttick-vs-setimmediate

  • 高超.我想知道为什么这不是公认的答案? (3认同)
  • 这个答案更有意义!谢谢@gsalgadotoledo :p 伙计,写你的名字比理解 nextTick 和 setImmediate 更难。 (2认同)

fre*_*ish 8

我无法重现你的结果setImmediate.它应该与nextTick(并且在我的测试中)相同,因为在这种情况下它们几乎完全相同.对此的唯一合理解释setImmediate是以某种方式同步,但事实并非如此.

根据NodeJS文档,唯一真正的区别是多次nextTick可能在一次循环迭代中触发(取决于maxTickDepth),而setImmediate每次迭代触发一次.


Ven*_*t.R 6

下面让您更清楚。

设置立即

  1. 当前轮询阶段完成后,它将执行脚本。
  2. 它是一个计时器模块函数,并且计时器函数是全局的,您可以在不使用require.
  3. 可以通过clearImmediate()清除它。
  4. 在 setTimeout() 和 setInterval() 之前设置 I/O 事件回调之后“立即”执行回调。

下一个刻度

  1. 它是NodeJS的进程全局对象函数。
  2. 所有传递给 process.nextTick() 的回调都将在事件循环继续之前得到解决。
  3. 允许用户处理错误。
  4. 有助于在事件循环继续之前再次尝试请求。

简单的代码片段。

console.log("I'm First");

setImmediate(function () {
  console.log('Im setImmediate');
});

console.log("I'm Second");

process.nextTick(function () {
  console.log('Im nextTick');
});

console.log("I'm Last");

/*
Output
$ node server.js
I'm First
I'm Second
I'm Last
Im nextTick
Im setImmediate
*/
Run Code Online (Sandbox Code Playgroud)