setImmediate与nextTick

本文翻译自:setImmediate vs. nextTick

Node.js version 0.10 was released today and introduced setImmediate . Node.js版本0.10已于今天发布,并引入了setImmediate The API changes documentation suggests using it when doing recursive nextTick calls. API更改文档建议在进行递归nextTick调用时使用它。

From what MDN says it seems very similar to process.nextTick . MDN看来,这似乎与process.nextTick非常相似。

When should I use nextTick and when should I use setImmediate ? 什么时候应该使用nextTick当我应该使用setImmediate


#1楼

参考:https://stackoom.com/question/12PAL/setImmediate与nextTick


#2楼

Use setImmediate if you want to queue the function behind whatever I/O event callbacks that are already in the event queue. 如果要将函数放在事件队列中已经存在的任何I / O事件回调后面,请使用setImmediate Use process.nextTick to effectively queue the function at the head of the event queue so that it executes immediately after the current function completes. 使用process.nextTick有效地将函数放在事件队列的开头,以便在当前函数完成后立即执行。

So in a case where you're trying to break up a long running, CPU-bound job using recursion, you would now want to use setImmediate rather than process.nextTick to queue the next iteration as otherwise any I/O event callbacks wouldn't get the chance to run between iterations. 因此,在您尝试使用递归分解长时间运行且受CPU限制的作业的情况下,您现在想使用setImmediate而不是process.nextTick将下一个迭代排队,因为否则所有I / O事件回调都不会没有机会在迭代之间运行。


#3楼

In the comments in the answer, it does not explicitly state that nextTick shifted from Macrosemantics to Microsemantics. 在答案的注释中,它没有明确声明nextTick从Macrosemantics转变为Microsemantics。

before node 0.9 (when setImmediate was introduced), nextTick operated at the start of the next callstack. 在节点0.9之前(引入setImmediate时),nextTick在下一个调用堆栈的开始处运行。

since node 0.9, nextTick operates at the end of the existing callstack, whereas setImmediate is at the start of the next callstack 从节点0.9开始,nextTick在现有调用栈的末尾运行,而setImmediate在下一个调用栈的末尾运行

check out https://github.com/YuzuJS/setImmediate for tools and details 查看https://github.com/YuzuJS/setImmediate以获取工具和详细信息


#4楼

As an illustration 作为说明

import fs from 'fs';
import http from 'http';

const options = {
  host: 'www.stackoverflow.com',
  port: 80,
  path: '/index.html'
};

describe('deferredExecution', () => {
  it('deferredExecution', (done) => {
    console.log('Start');
    setTimeout(() => console.log('TO1'), 0);
    setImmediate(() => console.log('IM1'));
    process.nextTick(() => console.log('NT1'));
    setImmediate(() => console.log('IM2'));
    process.nextTick(() => console.log('NT2'));
    http.get(options, () => console.log('IO1'));
    fs.readdir(process.cwd(), () => console.log('IO2'));
    setImmediate(() => console.log('IM3'));
    process.nextTick(() => console.log('NT3'));
    setImmediate(() => console.log('IM4'));
    fs.readdir(process.cwd(), () => console.log('IO3'));
    console.log('Done');
    setTimeout(done, 1500);
  });
});

will give the following output 将给出以下输出

Start
Done
NT1
NT2
NT3
TO1
IO2
IO3
IM1
IM2
IM3
IM4
IO1

I hope this can help to understand the difference. 我希望这可以帮助理解差异。


#5楼

I think I can illustrate this quite nicely. 我想我可以很好地说明这一点。 Since nextTick is called at the end of the current operation, calling it recursively can end up blocking the event loop from continuing. 由于nextTick在当前操作结束时被调用,因此以递归方式调用它可能最终阻止事件循环继续进行。 setImmediate solves this by firing in the check phase of the event loop, allowing event loop to continue normally. setImmediate通过在事件循环的检查阶段触发来解决此问题,从而允许事件循环正常继续。

   ┌───────────────────────┐
┌─>│        timers         │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     I/O callbacks     │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     idle, prepare     │
│  └──────────┬────────────┘      ┌───────────────┐
│  ┌──────────┴────────────┐      │   incoming:   │
│  │         poll          │<─────┤  connections, │
│  └──────────┬────────────┘      │   data, etc.  │
│  ┌──────────┴────────────┐      └───────────────┘
│  │        check          │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
└──┤    close callbacks    │
   └───────────────────────┘

source: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/ 来源: https : //nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/

Notice that the check phase is immediately after the poll phase. 请注意,检查阶段紧接在轮询阶段之后。 This is because the poll phase and I/O callbacks are the most likely places your calls to setImmediate are going to run. 这是因为轮询阶段和I / O回调是您对setImmediate的调用最有可能运行的地方。 So ideally most of those calls will actually be pretty immediate, just not as immediate as nextTick which is checked after every operation and technically exists outside of the event loop. 因此,理想情况下,这些调用中的大多数实际上实际上是立即调用的,而不是像nextTick那样立即nextTicknextTick在每次操作后都要检查,并且从技术上讲是存在于事件循环之外的。

Let's take a look at a little example of the difference between setImmediate and process.nextTick : 让我们看一下setImmediateprocess.nextTick之间的区别的一个小例子:

function step(iteration) {
  if (iteration === 10) return;
  setImmediate(() => {
    console.log(`setImmediate iteration: ${iteration}`);
    step(iteration + 1); // Recursive call from setImmediate handler.
  });
  process.nextTick(() => {
    console.log(`nextTick iteration: ${iteration}`);
  });
}
step(0);

Let's say we just ran this program and are stepping through the first iteration of the event loop. 假设我们只是运行了该程序,并逐步完成了事件循环的第一次迭代。 It will call into the step function with iteration zero. 它将以零迭代次数调用step函数。 It will then register two handlers, one for setImmediate and one for process.nextTick . 然后它将注册两个处理程序,一个用于setImmediate ,一个用于process.nextTick We then recursively call this function from the setImmediate handler which will run in the next check phase. 然后,我们从setImmediate处理程序中递归调用此函数,该处理程序将在下一个检查阶段运行。 The nextTick handler will run at the end of the current operation interrupting the event loop, so even though it was registered second it will actually run first. nextTick处理程序将在当前操作结束时运行,中断事件循环,因此,即使它已被第二次注册,它实际上也会首先运行。

The order ends up being: nextTick fires as current operation ends, next event loop begins, normal event loop phases execute, setImmediate fires and recursively calls our step function to start the process all over again. 最终的顺序是:当前操作结束时将触发nextTick ,下一个事件循环将开始,正常事件循环阶段将执行, setImmediate触发并递归调用我们的step函数以重新开始该过程。 Current operation ends, nextTick fires, etc. 当前操作结束, nextTick触发等。

The output of the above code would be: 上面代码的输出为:

nextTick iteration: 0
setImmediate iteration: 0
nextTick iteration: 1
setImmediate iteration: 1
nextTick iteration: 2
setImmediate iteration: 2
nextTick iteration: 3
setImmediate iteration: 3
nextTick iteration: 4
setImmediate iteration: 4
nextTick iteration: 5
setImmediate iteration: 5
nextTick iteration: 6
setImmediate iteration: 6
nextTick iteration: 7
setImmediate iteration: 7
nextTick iteration: 8
setImmediate iteration: 8
nextTick iteration: 9
setImmediate iteration: 9

Now let's move our recursive call to step into our nextTick handler instead of the setImmediate . 现在,让我们继续我们的递归调用step到我们nextTick处理程序,而不是setImmediate

function step(iteration) {
  if (iteration === 10) return;
  setImmediate(() => {
    console.log(`setImmediate iteration: ${iteration}`);
  });
  process.nextTick(() => {
    console.log(`nextTick iteration: ${iteration}`);
    step(iteration + 1); // Recursive call from nextTick handler.
  });
}
step(0);

Now that we have moved the recursive call to step into the nextTick handler things will behave in a different order. 现在我们已经搬到了递归调用stepnextTick处理事情会以不同的顺序行为。 Our first iteration of the event loop runs and calls step registering a setImmedaite handler as well as a nextTick handler. 事件循环的第一个迭代运行并调用step注册setImmedaite处理程序以及nextTick处理程序。 After the current operation ends our nextTick handler fires which recursively calls step and registers another setImmediate handler as well as another nextTick handler. 当前操作结束后,将触发nextTick处理程序,该处理程序递归调用step并注册另一个setImmediate处理程序以及另一个nextTick处理程序。 Since a nextTick handler fires after the current operation, registering a nextTick handler within a nextTick handler will cause the second handler to run immediately after the current handler operation finishes. 由于nextTick处理火灾当前操作之后,登记nextTick一个内处理程序nextTick处理程序将导致第二处理程序,以当前的处理程序的操作完成后立即运行。 The nextTick handlers will keep firing, preventing the current event loop from ever continuing. nextTick处理程序将继续触发,从而防止当前事件循环继续进行。 We will get through all our nextTick handlers before we see a single setImmediate handler fire. 在看到单个setImmediate处理程序启动之前,我们将遍历所有nextTick处理程序。

The output of the above code ends up being: 上面代码的输出最终是:

nextTick iteration: 0
nextTick iteration: 1
nextTick iteration: 2
nextTick iteration: 3
nextTick iteration: 4
nextTick iteration: 5
nextTick iteration: 6
nextTick iteration: 7
nextTick iteration: 8
nextTick iteration: 9
setImmediate iteration: 0
setImmediate iteration: 1
setImmediate iteration: 2
setImmediate iteration: 3
setImmediate iteration: 4
setImmediate iteration: 5
setImmediate iteration: 6
setImmediate iteration: 7
setImmediate iteration: 8
setImmediate iteration: 9

Note that had we not interrupted the recursive call and aborted it after 10 iterations then the nextTick calls would keep recursing and never letting the event loop continue to the next phase. 请注意,如果我们没有中断递归调用并在10次迭代后中止它,则nextTick调用将继续递归,并且永远不会让事件循环继续进行到下一个阶段。 This is how nextTick can become blocking when used recursively whereas setImmediate will fire in the next event loop and setting another setImmediate handler from within one won't interrupt the current event loop at all, allowing it to continue executing phases of the event loop as normal. 这就是nextTick在递归使用时会变为阻塞的方式,而setImmediate将在下一个事件循环中触发,并且从一个内部设置另一个setImmediate处理程序根本不会中断当前事件循环,从而使其能够照常继续执行事件循环的各个阶段。

Hope that helps! 希望有帮助!

PS - I agree with other commenters that the names of the two functions could easily be swapped since nextTick sounds like it's going to fire in the next event loop rather than the end of the current one, and the end of the current loop is more "immediate" than the beginning of the next loop. PS-我同意其他评论者的观点,这两个函数的名称可以轻松交换,因为nextTick听起来像是在下一个事件循环中触发,而不是在当前事件的末尾触发,而当前循环的结束更像是“立即”,而不是下一个循环的开始。 Oh well, that's what we get as an API matures and people come to depend on existing interfaces. 哦,这就是随着API的成熟以及人们开始依赖现有接口而获得的。


#6楼

In simple terms, process.NextTick() would executed at next tick of event loop. 简单来说,process.NextTick()将在事件循环的下一个计时执行。 However, the setImmediate, basically has a separate phase which ensures that the callback registered under setImmediate() will be called only after the IO callback and polling phase. 但是,setImmediate本质上具有一个单独的阶段,该阶段确保仅在IO回调和轮询阶段之后才调用在setImmediate()下注册的回调。

Please refer to this link for nice explanation: https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c 请参考此链接以获得更好的解释: https : //medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and -its-metrics-c4907b19da4c

简化的事件循环事件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值