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

时间:2014-06-09 09:25:17

标签: javascript node.js web

这两者之间有什么区别,我何时会使用另一个?

9 个答案:

答案 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毫秒。