【发布时间】:2014-07-29 19:34:30
【问题描述】:
这两者有什么区别,我什么时候会使用其中一个?
【问题讨论】:
-
我今天了解到,Chrome 完全没有 setImmediate()
标签: javascript node.js
这两者有什么区别,我什么时候会使用其中一个?
【问题讨论】:
标签: javascript node.js
要深入了解它们,请完成事件循环阶段。
立即设置: 它在“检查”阶段执行。 check 阶段在 I/O 阶段之后调用。
设置超时: 它在“计时器”阶段执行。 timer 阶段是第一个阶段,但在 I/O 阶段和 Check 阶段之后被调用。
要以确定的方式获得输出,这将取决于事件循环处于哪个阶段;因此,我们可以使用两个功能。
【讨论】:
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)。
【讨论】:
setTimeout(fn,0) 可用于防止浏览器在大规模更新时冻结。例如在 websocket.onmessage 中,您可能有 html 更改,如果消息不断出现,使用 setImmidiate 时浏览器可能会冻结
【讨论】:
我认为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
【讨论】:
关于事件循环如何工作并消除一些误解的精彩文章。 http://voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout/
引用文章:
setImmediate 回调在 I/O 队列回调完成或超时后调用。 setImmediate 回调放在 Check Queue 中,在 I/O Queue 之后处理。
setTimeout(fn, 0) 回调被放置在 Timer Queue 中,将在 I/O 回调和 Check Queue 回调之后被调用。作为事件循环,每次迭代都会先处理定时器队列,所以先执行哪一个取决于事件循环在哪个阶段。
【讨论】:
使用 setImmediate() 不阻塞事件循环。一旦当前事件完成,回调将在下一个事件循环上运行。
使用 setTimeout() 控制延迟。该函数将在指定的延迟后运行。最小延迟为 1 毫秒。
【讨论】:
总是使用setImmediate,除非你真的确定你需要setTimeout(,0)(但我什至无法想象,有什么用)。 setImmediate 回调几乎总是在 setTimeout(,0) 之前执行,除非在第一次滴答和 setImmediate 回调中调用。
【讨论】:
setTimeout 应该是首选,setImmediate 仅在必要时使用。
setImmediate() 是安排在 I/O 事件回调之后,setTimeout 和 setInterval 之前立即执行回调。
setTimeout() 是安排在延迟毫秒后执行一次回调。
文件是这么说的。
setTimeout(function() {
console.log('setTimeout')
}, 0)
setImmediate(function() {
console.log('setImmediate')
})
如果您运行上面的代码,结果将是这样的......即使当前文档声明“在 I/O 事件回调之后和 setTimeout 和 setInterval 之前安排回调的‘立即’执行。” ..
结果..
设置超时
立即设置
如果您将示例包装在另一个计时器中,它总是会打印 setImmediate 后跟 setTimeout。
setTimeout(function() {
setTimeout(function() {
console.log('setTimeout')
}, 0);
setImmediate(function() {
console.log('setImmediate')
});
}, 10);
【讨论】: