这两者之间有什么区别,我何时会使用另一个?
答案 0 :(得分:56)
setTimeout 就像延迟完成后调用函数一样。每当调用一个函数时,它不会立即执行,而是排队,以便在所有执行和当前排队的事件处理程序首先完成后执行。 setTimeout(,0)实质上是指在执行当前队列中的所有当前函数之后执行。不能保证可以花多长时间。
setImmediate 在这方面类似,只是它不使用函数队列。它检查I / O事件处理程序的队列。如果处理了当前快照中的所有I / O事件,它将执行回调。在最后一个I / O处理程序有点像process.nextTick之后,它会立即对它们进行排队。所以它更快。
此外(setTimeout,0)将会很慢,因为它会在执行前至少检查一次计时器。有时它可能慢两倍。这是一个基准。
var Suite = require('benchmark').Suite
var fs = require('fs')
var suite = new Suite
suite.add('deffered.resolve()', function(deferred) {
deferred.resolve()
}, {defer: true})
suite.add('setImmediate()', function(deferred) {
setImmediate(function() {
deferred.resolve()
})
}, {defer: true})
suite.add('setTimeout(,0)', function(deferred) {
setTimeout(function() {
deferred.resolve()
},0)
}, {defer: true})
suite
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').pluck('name'));
})
.run({async: true})
输出
deffered.resolve() x 993 ops/sec ±0.67% (22 runs sampled)
setImmediate() x 914 ops/sec ±2.48% (57 runs sampled)
setTimeout(,0) x 445 ops/sec ±2.79% (82 runs sampled)
第一个给出了最快可能的呼叫的想法。你可以检查自己setTimeout被调用的次数是其他的一半。还记得setImmediate会调整你的文件系统调用。所以在负载下它会表现得更少。我认为setTimeout不会做得更好。
setTimeout是一段时间后调用函数的非侵入式方法。就像它在浏览器中一样。它可能不适合服务器端(想想为什么我使用了benchmark.js而不是setTimeout)。
答案 1 :(得分:12)
关于事件循环如何工作的一篇很棒的文章,并清除了一些误解。 http://voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout/
引用文章:
在I / O队列回调完成或超时后调用 setImmediate
回调。 setImmediate回调放在Check Queue中,在I / O队列之后处理。
setTimeout(fn, 0)
回调放在Timer Queue中,并在I / O回调和Check Queue回调后调用。作为事件循环,在每次迭代中首先处理计时器队列,因此首先执行哪一个取决于哪个阶段事件循环。
答案 2 :(得分:6)
setImmediate()用于在I / O事件回调之后以及setTimeout和setInterval之前安排立即执行回调。
setTimeout()是在延迟毫秒后安排执行一次性回调。
这就是文件所说的内容。
setTimeout(function() {
console.log('setTimeout')
}, 0)
setImmediate(function() {
console.log('setImmediate')
})
如果你运行上面的代码,结果将是这样的...即使当前的文档指出"安排"立即"在I / O事件回调之后以及在setTimeout和setInterval之前执行回调。" ..
结果..
setTimeout
setImmediate
如果将示例包装在另一个计时器中,它总是打印setImmediate,后跟setTimeout。
setTimeout(function() {
setTimeout(function() {
console.log('setTimeout')
}, 0);
setImmediate(function() {
console.log('setImmediate')
});
}, 10);
答案 3 :(得分:2)
始终使用setImmediate
,除非您确定需要setTimeout(,0)
(但我无法想象,为什么)。 setImmediate
回调几乎总是在setTimeout(,0)
之前执行,除非在第一个勾号和setImmediate
回调中调用。
答案 4 :(得分:0)
我认为 Navya S 的答案不正确,这是我的测试代码:
let set = new Set();
function orderTest() {
let seq = [];
let add = () => set.add(seq.join());
setTimeout(function () {
setTimeout(function () {
seq.push('setTimeout');
if (seq.length === 2) add();
}, 0);
setImmediate(function () {
seq.push('setImmediate');
if (seq.length === 2) add();
});
}, 10);
}
// loop 100 times
for (let i = 0; i < 100; i++) {
orderTest();
}
setTimeout(() => {
// will print one or two items, it's random
for (item of set) {
console.log(item);
}
}, 100);
解释是here
答案 5 :(得分:0)
setTimeout(fn,0)可用于防止浏览器在大量更新中冻结。例如在websocket.onmessage中,您可能有html更改,如果消息不断出现,浏览器可能会在使用setImmidiate时冻结
答案 6 :(得分:0)
对提供的答案完全不满意。我在这里发布了我认为是更好的答案:https://stackoverflow.com/a/56724489/5992714
问题可能是Why is the behavior of setTimeout(0) and setImmediate() undefined when used in the main module ?
的重复项答案 7 :(得分:0)
要深入了解它们,请一次进入事件循环阶段。
立即设置: 它在“检查”阶段执行。在I / O阶段之后调用 check 阶段。
SetTimeOut: 它在“计时器”阶段执行。 计时器阶段是第一阶段,但在 I / O 阶段以及 Check 阶段之后被调用。
要以确定性的方式获取输出,将取决于事件循环处于哪个阶段。因此,我们可以使用两个函数。
答案 8 :(得分:-4)
使用setImmediate()来阻止事件循环。当完成当前循环时,回调将在下一个事件循环上运行。
使用setTimeout()来控制延迟。该函数将在指定的延迟后运行。最小延迟为1毫秒。