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


回答:


71

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)

最初のものは、可能な限り最速の呼び出しのアイデアを提供します。setTimeoutが他の半分の回数呼び出されるかどうかを自分で確認できます。また、setImmediateがファイルシステムの呼び出しに適応することを忘れないでください。したがって、負荷がかかるとパフォーマンスが低下します。setTimeoutの方がうまくいくとは思いません。

setTimeoutは、しばらくしてから関数を呼び出す邪魔にならない方法です。ブラウザの場合と同じです。サーバー側には適していない可能性があります(setTimeoutではなくbenchmark.jsを使用した理由を考えてください)。


3
setTimeoutは、5回ネストされた場合、少なくとも4ミリ秒の強制遅延の影響を受けることに注意することが重要です。 HTML仕様を参照
Jack Allan

(他の回答から)このソースは、ここでは文の一部に反論するようだ:voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout
ドミトリ・ザイツェフ

17

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

記事の引用:

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

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


setTimeoutキューは、I / Oコールバックの前に処理されます。参照:nodejs.org/en/docs/guides/event-loop-timers-and-nexttick
人間

6

setImmediate()は、I / Oイベントのコールバックの後、setTimeoutおよびsetIntervalの前にコールバックの即時実行をスケジュールします。

setTimeout()は、遅延ミリ秒後に1回限りのコールバックの実行をスケジュールします。

これは文書が言っていることです。

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最初の結果で、setImmediateの前にsetTimeoutが最初に実行された理由を説明してください
Agus Syahputra 2016年

2
@AgusSyahputraこれをチェックしてください:github.com/nodejs/node-v0.x-archive/issues/25788
Rodrigo

1
SetImmediate文句を言わないのsetTimeoutとのsetInterval常に前に実行
Mithun GS

2

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


1
setImmediateの代わりにsetTimeoutを使用する主な理由は、setImmediateが実装されていないブラウザーでコードを実行する必要があるためです。それでも、シムを作成するだけです。
Gregory Magarshak 2015年

9
これは不健全なアドバイスです。すべてが最初に実行するように要求された場合、非同期実行の新たなパフォーマンス特性は、最後のキューイングと比較してジャンクになります。 setTimeout必要であることがsetImmediate示された場合にのみ使用され、頼りになるはずです。
リッチリマー2017

1

提供された回答に完全に満足していません。私はここにもっと良い答えだと思うものを投稿しました:https//stackoverflow.com/a/56724489/5992714

質問は、メインモジュールで使用されたときにsetTimeout(0)とsetImmediate()の動作が未定義である理由の重複の可能性があります。


1
2つの質問にまったく同じ回答を投稿しないでください。質問が異なる場合は、それぞれに答えを調整します。それらが同じである場合は、フラグを立てるか投票して、重複として1つを閉じます。
TomZych19年

@TomZychは指摘しました。
人間

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の相と同様にチェックフェーズ。

決定論的な方法で出力を取得するには、イベントループがどのフェーズであるかによって異なります。したがって、2つのうちの関数を使用できます。


-4

イベントループをブロックしないようにするには、setImmediate()を使用します。コールバックは、現在のイベントループが完了するとすぐに、次のイベントループで実行されます。

制御された遅延にはsetTimeout()を使用します。関数は、指定された遅延後に実行されます。最小遅延は1ミリ秒です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.