NodeJS-setTimeout(fn,0)与setImmediate(fn)


Answers:


71

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)。


3
重要的是要注意,如果嵌套五次,则setTimeout至少要经受四毫秒的强制延迟。 参见html规范
Jack Allan

此消息源(来自其他答案)似乎驳斥了此处的某些陈述:voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout
Dmitri Zaitsev

17

一篇有关事件循环如何工作并清除一些误解的出色文章。 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回调之后被调用。作为事件循环,在每次迭代中首先处理计时器队列,因此哪个事件将首先执行取决于哪个阶段的事件循环。


setTimeout队列在I / O回调之前进行处理。参考:nodejs.org/en/docs/guides/event-loop-timers-and-nexttick
人类,

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);

那么,什么时候您会偏爱另一个?
Shlomi Schwartz 2014年

21
您没有解释为什么您所显示的会发生。这个答案对我没有用。
克林特·伊斯特伍德

3
@Savannah在您的第一个结果中,请解释为什么setTimeout首先在setImmediate之前执行
Agus Syahputra


1
SetImmediate不会一直在setTimeout和setInterval之前执行
Mithun GS

2

始终使用setImmediate,除非您真的确定需要使用setTimeout(,0)(但我什至无法想象这是做什么用的)。setImmediate回调几乎总是在之前执行setTimeout(,0),除非是在第一个tick和setImmediate回调中调用时。


1
我要说使用setTimeout而不是setImmediate的主要原因是您的代码需要由未实现setImmediate的浏览器执行。即使这样,您也可以创建匀场片。
Gregory Magarshak'3

9
这是不明智的建议。如果一切都要求先行,那么与最后的排队相比,异步执行的新兴性能特征将变得垃圾。 setTimeout应该是首选,setImmediate仅在必要时使用。
Rich Remer


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);

解释在这里


0

setTimeout(fn,0)可用于防止浏览器冻结在大规模更新中。例如在websocket.onmessage中,您可能会有html更改,并且如果消息不断出现,则使用setImmidiate时浏览器可能会冻结


0

要深入了解它们,请进入事件循环阶段。

SetImmediate: 在“检查”阶段执行。该检查阶段的I / O阶段后调用。

SetTimeOut: 在“计时器”阶段执行。该计时器阶段是第一阶段,但后称为I / O阶段以及在检查阶段。

为了以确定的方式获得输出,将取决于事件循环处于哪个阶段。因此,我们可以使用两个函数。


-4

使用setImmediate()来不阻塞事件循环。当前事件完成后,回调将在下一个事件循环上运行。

使用setTimeout()来控制延迟。该功能将在指定的延迟后运行。最小延迟为1毫秒。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.