Ben*_*aum 328 javascript node.js setimmediate
Node.js版本0.10今天发布并推出 setImmediate.该API的变化文档建议做递归时使用它nextTick调用.
从MDN看起来它看起来非常相似process.nextTick.
我nextTick应该何时使用,何时使用setImmediate?
Joh*_*yHK 494
使用setImmediate如果要排队的任何I/O事件回调中已经存在的事件队列后面的功能.用于process.nextTick在事件队列的头部有效地对函数进行排队,以便在当前函数完成后立即执行.
因此,在您尝试使用递归分解长时间运行的CPU绑定作业的情况下,您现在希望使用setImmediate而不是process.nextTick排队下一次迭代,否则任何I/O事件回调都不会有机会在迭代之间运行.
Dra*_*anS 57
作为例证
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);
});
});
Run Code Online (Sandbox Code Playgroud)
将给出以下输出
Start
Done
NT1
NT2
NT3
TO1
IO2
IO3
IM1
IM2
IM3
IM4
IO1
Run Code Online (Sandbox Code Playgroud)
我希望这有助于理解其中的差异.
Che*_*hev 41
我想我可以很好地说明这一点.由于nextTick在当前操作结束时调用,因此递归调用它最终会阻止事件循环继续.setImmediate通过在事件循环的检查阶段触发来解决这个问题,允许事件循环正常继续.
?????????????????????????
??>? timers ?
? ?????????????????????????
? ?????????????????????????
? ? I/O callbacks ?
? ?????????????????????????
? ?????????????????????????
? ? idle, prepare ?
? ????????????????????????? ?????????????????
? ????????????????????????? ? incoming: ?
? ? poll ?<?????? connections, ?
? ????????????????????????? ? data, etc. ?
? ????????????????????????? ?????????????????
? ? check ?
? ?????????????????????????
? ?????????????????????????
???? close callbacks ?
?????????????????????????
Run Code Online (Sandbox Code Playgroud)
来源:https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
请注意,检查阶段紧接在轮询阶段之后.这是因为轮询阶段和I/O回调是您的调用最有可能setImmediate运行的地方.因此理想情况下,大多数这些调用实际上都是非常直接的,只是没有nextTick在每次操作之后检查并且在技术上存在于事件循环之外.
让我们看一下setImmediate和之间区别的一个小例子process.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);
Run Code Online (Sandbox Code Playgroud)
假设我们刚刚运行了这个程序,并且正在逐步完成事件循环的第一次迭代.它将调用step迭代零的函数.然后它将注册两个处理程序,一个用于setImmediate,一个用于process.nextTick.然后我们从setImmediate处理程序递归调用此函数,该处理程序将在下一个检查阶段运行.该nextTick处理器将在当前的运行中断事件循环结束时运行,所以即使它注册的第二它实际上将首先运行.
该命令最终成为:nextTick当前操作结束时触发,下一个事件循环开始,正常事件循环阶段执行,setImmediate触发并递归调用我们的step函数以重新开始该过程.当前操作结束,nextTick火灾等
上面代码的输出将是:
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
Run Code Online (Sandbox Code Playgroud)
现在让我们将递归调用移动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);
Run Code Online (Sandbox Code Playgroud)
现在我们已经将递归调用移动step到nextTick处理程序中,事物将以不同的顺序运行.我们对事件循环的第一次迭代运行并调用step注册setImmedaite处理程序和nextTick处理程序.当前操作结束后,我们的nextTick处理程序触发,递归调用step并注册另一个setImmediate处理程序以及另一个nextTick处理程序.由于nextTick处理程序在当前操作之后触发,因此nextTick在nextTick处理程序中注册处理程序将导致第二个处理程序在当前处理程序操作完成后立即运行.该nextTick处理程序将持续开火,阻止当前事件循环从不断持续.nextTick在看到单个setImmediate处理程序触发之前,我们将通过所有处理程序.
上述代码的输出最终为:
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
Run Code Online (Sandbox Code Playgroud)
请注意,如果我们没有中断递归调用并在10次迭代后中止它,那么nextTick调用将保持递归并且永远不会让事件循环继续到下一阶段.这是如何nextTick在递归使用时变为阻塞,而setImmediate在下一个事件循环中触发并setImmediate从一个内部设置另一个处理程序将根本不中断当前事件循环,允许它继续正常执行事件循环的阶段.
希望有所帮助!
PS - 我同意其他评论者的说法,两个函数的名称可以很容易地交换,因为nextTick它会在下一个事件循环中触发,而不是在当前循环结束时触发,并且当前循环的结束更"立即" "比下一个循环的开始.哦,这就是我们在API成熟时所获得的,人们开始依赖现有的接口.
Jay*_*Zee 29
在答案的评论中,它没有明确说明nextTick从Macrosemantics转移到Microsemantics.
在节点0.9之前(当引入setImmediate时),nextTick在下一个callstack的开始处运行.
从节点0.9开始,nextTick在现有callstack的末尾运行,而setImmediate在下一个callstack的开头
有关工具和详细信息,请查看https://github.com/YuzuJS/setImmediate
Bri*_*ams 10
这里有一些很好的答案,详细说明了它们是如何工作的。
只需添加一个回答特定问题的答案:
我应该什么时候用
nextTick,什么时候用setImmediate?
setImmediate.在Node.js的事件循环,定时器和process.nextTick()文档包括以下内容:
我们建议开发人员
setImmediate()在所有情况下使用,因为它更容易推理(并且它导致代码与更广泛的环境兼容,例如浏览器 JS。)
在文档的早些时候,它警告说process.nextTick可能会导致......
一些糟糕的情况,因为它允许您通过递归
process.nextTick()调用来“饿死”您的 I/O,从而防止事件循环到达轮询阶段。
事实证明,process.nextTick甚至可以饿死Promises:
Promise.resolve().then(() => { console.log('this happens LAST'); });
process.nextTick(() => {
console.log('all of these...');
process.nextTick(() => {
console.log('...happen before...');
process.nextTick(() => {
console.log('...the Promise ever...');
process.nextTick(() => {
console.log('...has a chance to resolve');
})
})
})
})
Run Code Online (Sandbox Code Playgroud)
另一方面,setImmediate“更容易推理”并避免了这些类型的问题:
Promise.resolve().then(() => { console.log('this happens FIRST'); });
setImmediate(() => {
console.log('this happens LAST');
})
Run Code Online (Sandbox Code Playgroud)
因此,除非对 的独特行为有特定需求,否则process.nextTick推荐的方法是“在所有情况下使用setImmediate()”。
简单来说,process.NextTick()将在事件循环的下一个刻度处执行.但是,setImmediate基本上有一个单独的阶段,它确保只在IO回调和轮询阶段之后才会调用在setImmediate()下注册的回调.
请参考此链接以获得更好的解释:https: //medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and -它的度量-c4907b19da4c