web-dev-qa-db-ja.com

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

これらの2つの違いは何ですか?また、いつ一方を使用しますか?

69
Shlomi Schwartz

setTimeoutは、遅延が終了した後に関数を呼び出すようなものです。関数が呼び出されると、すぐに実行されるのではなく、キューに入れられ、実行中および現在キューに入れられているすべてのイベントハンドラーが最初に終了した後に実行されます。 setTimeout(、0)は、本質的に、現在のキュー内のすべての現在の関数が実行された後に実行することを意味します。所要時間については保証できません。

setImmediateはこの点で似ていますが、関数のキューを使用しない点が異なります。 I/Oイベントハンドラのキューをチェックします。現在のスナップショット内のすべてのI/Oイベントが処理されると、コールバックが実行されます。 process.nextTickのような最後のI/Oハンドラーの直後にそれらをキューに入れます。だから、高速です。

また、(setTimeout、0)は、実行前に少なくとも1回タイマーをチェックするため、遅くなります。時には2倍遅くなることがあります。これがベンチマークです。

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)

1つ目は、可能な限り高速の通話のアイデアです。 setTimeoutが他の半分の回数呼び出されるかどうかを確認できます。また、setImmediateはファイルシステムの呼び出しに合わせて調整することを忘れないでください。そのため、負荷がかかるとパフォーマンスが低下します。 setTimeoutの方が良いとは思いません。

setTimeoutは、しばらくしてから関数を呼び出す邪魔にならない方法です。ブラウザと同じです。サーバー側には向いていないかもしれません(なぜsetTimeoutではなくベンチマークを使用したのかを考えてください)。

66
user568109

イベントループがどのように機能し、いくつかの誤解を解消する方法についての素晴らしい記事。 http://voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout/

記事の引用:

setImmediateコールバックは、I/Oキューコールバックが終了またはタイムアウトした後に呼び出されます。 setImmediateコールバックはチェックキューに配置され、I/Oキューの後に処理されます。

setTimeout(fn, 0)コールバックはタイマーキューに配置され、I/Oコールバックとチェックキューコールバックの後に呼び出されます。イベントループとして、各反復で最初にタイマーキューを処理するため、最初に実行されるのはどのフェーズイベントループかによって異なります。

16
Aman Gupta

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);
6
Navya S

setTimeout(,0)が本当に必要であることが確かでない限り、常にsetImmediateを使用してください(しかし、私は想像することすらできません)。 setImmediateコールバックは、ほとんどの場合、setTimeout(,0)の前に実行されます。ただし、最初のティックおよびsetImmediateコールバックで呼び出される場合を除きます。

2
vkurchatkin

提供された回答にまったく不満。私はここでより良い答えだと思うものを投稿しました: https://stackoverflow.com/a/56724489/5992714

質問は setTimeout(0)とsetImmediate()の動作がメインモジュールで使用された場合に定義されないのはなぜですか?

0
bigdatamann

setTimeout(fn、0)は、大規模な更新で​​ブラウザがフリーズするのを防ぐために使用できます。たとえば、websocket.onmessageでは、htmlの変更があり、setImmidiateを使用すると、メッセージが引き続き表示される場合、ブラウザがフリーズする場合があります

0
Lior Goldemberg

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
笑笑十年