【问题标题】:NodeJS - setTimeout(fn,0) vs setImmediate(fn)NodeJS - setTimeout(fn,0) vs setImmediate(fn)
【发布时间】:2014-07-29 19:34:30
【问题描述】:

这两者有什么区别,我什么时候会使用其中一个?

【问题讨论】:

标签: javascript node.js


【解决方案1】:

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

立即设置: 它在“检查”阶段执行。 check 阶段在 I/O 阶段之后调用。

设置超时: 它在“计时器”阶段执行。 timer 阶段是第一个阶段,但在 I/O 阶段和 Check 阶段之后被调用。

要以确定的方式获得输出,这将取决于事件循环处于哪个阶段;因此,我们可以使用两个功能。

【讨论】:

    【解决方案2】:

    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(fn,0) 可用于防止浏览器在大规模更新时冻结。例如在 websocket.onmessage 中,您可能有 html 更改,如果消息不断出现,使用 setImmidiate 时浏览器可能会冻结

    【讨论】:

      【解决方案4】:

      我认为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】:

        关于事件循环如何工作并消除一些误解的精彩文章。 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 回调之后被调用。作为事件循环,每次迭代都会先处理定时器队列,所以先执行哪一个取决于事件循环在哪个阶段。

        【讨论】:

        【解决方案6】:

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

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

        【讨论】:

          【解决方案7】:

          总是使用setImmediate,除非你真的确定你需要setTimeout(,0)(但我什至无法想象,有什么用)。 setImmediate 回调几乎总是在 setTimeout(,0) 之前执行,除非在第一次滴答和 setImmediate 回调中调用。

          【讨论】:

          • 我会说使用 setTimeout 而不是 setImmediate 的主要原因是您的代码需要由没有实现 setImmediate 的浏览器执行。即使这样,您也可以创建一个 shim。
          • 这是不合理的建议。如果一切都要求先行,那么与最后的排队相比,异步执行的紧急性能特征将是垃圾。 setTimeout 应该是首选,setImmediate 仅在必要时使用。
          【解决方案8】:

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

          【讨论】:

          • 那么你什么时候会更喜欢哪一个呢?
          • 你没有解释为什么你显示的会发生。这个答案对我没有用。
          • @Savannah 在你的第一个结果中,请解释为什么 setTimeout 在 setImmediate 之前先执行
          • @AgusSyahputra 看看这个:github.com/nodejs/node-v0.x-archive/issues/25788
          • SetImmediate 不会在 setTimeout 和 setInterval 之前执行
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-08-13
          • 2022-08-03
          • 2021-10-11
          • 1970-01-01
          • 2012-07-17
          相关资源
          最近更新 更多