2016-07-13 7 views
2

毎秒1回機能を実行したいが、機能自体は3秒かかる。setInterval nodejsの奇妙な振る舞い

var seconds = 3; 

setInterval(
    function(){ 
      console.info(new Date().toString()); 
      var waitTill = new Date(new Date().getTime() + seconds * 1000); 
      while(waitTill > new Date()){} 
    },1000 
); 

及び式Iに記載の各反復である:

Wed Jul 13 2016 09:49:07 GMT+0300 (IDT) 
Wed Jul 13 2016 09:49:14 GMT+0300 (IDT) 
Wed Jul 13 2016 09:49:21 GMT+0300 (IDT) 
Wed Jul 13 2016 09:49:28 GMT+0300 (IDT) 

結果は、各間隔が、私は次のサンプルコードを書いた<function execution time>*2+<setInterval delay>

の差に実行されることですドキュメントにはこの動作が記載されていません。私が考えた結果は、インターバル関数の実行にどれくらいの時間がかかっても、各反復は1秒後に実行されるということです。

何が起こっているのですか?

この問題に関する情報は非常に高く評価されます。

ありがとうございました!

更新

Nodejs 6.3.0を使用して

ブラウザ上でこのコードを試してみました...グーグルクロームは...ここ間隔はまだ奇妙である、3秒ごとに実行されます。あなたのコメントのすべてのための

更新

おかげで、はっきりしていない最後の事。 NodeJSでsetInterval()を1秒に設定し、関数の実行に3秒かかる場合、次の実行は4秒または3秒ではなく7秒です。それは私にとっては本当に奇妙な行動に見えます。それは容認できる行動ですか?

+0

@Andreas:NodeJSはシングルスレッドです。 JavaScriptは*ではありません。 –

答えて

4

ドキュメントはこの動作に

NodeJSのdocumentation for setIntervalを述べていない特徴的にそれがタスクを繰り返しすること以外に、その動作について、事実上何も、述べていません。

私はそれがなると思った結果が、各反復は関係なく、あなたが実行を重複している可能性を意味する場合はインターバル機能の実行が

かかりますどのくらいの時間が1秒後に実行しないということですNodeJSではできません。 1つのスレッドでコードを実行します。

各反復が最後に完了してから1秒後に実行されることを期待している場合、これは伝統的にはsetIntervalの動作ではありません。 setIntervalには、現在使用している実装に応じて少なくとも2つの異なる動作がありました。で次の繰り返しをスケジューリングするか、現在の末尾にあるにスケジューリングします。それはブラウザだけです。 been standardized for browsers以降ですが、NodeJSはブラウザではなく、同じように動作する必要はありません。 (実際には、別の方法ではありません:ブラウザでは、数字を返すのにsetIntervalが必要です; NodeJSではオブジェクトを返します)。タイマーはJavaScriptの機能ではなく、機能ですホスト環境の

代わりに、以前に終了してからもう一度もう一度実行するには、関数の最後にsetTimeoutを使用して、次の1つを後で実行するようにスケジュールします。

あなたの編集再

:私はしたsetInterval()を1秒に設定しており、次回の実行でも7秒の代わりに、4秒以上である理由関数実行は、3秒かかりNodeJS、中

理由3秒。それは私にとっては本当に奇妙な行動に見えます。それは容認できる行動ですか?

はい。 (私の見解では)奇妙で驚くべきことですが、NodeJSはsetIntervalのためにそれ自身の振る舞いを決定します。したがって、は受け入れ可能なです。私の実験(下)では、関数の前回の実行時間を測定するように見えますが、は、をタイマの長さに加算すると、再度発生する前にlastExecutionLength + desiredIntervalになります。これはブラウザの仕様と著しく異なりますが、NodeJSはブラウザではありません。ここで

は私のテストスクリプトは次のとおりです。

let counter = 0; 
let timeAtEndOfLastExecution = 0; 
let timer = null; 

function log(msg) { 
    console.log(Date.now() + ": " + msg); 
} 

function tick() { 
    let start = Date.now(); 
    if (timeAtEndOfLastExecution) { 
     log("tick (" + (Date.now() - timeAtEndOfLastExecution) + "ms)"); 
    } else { 
     log("tick"); 
    } 
    if (++counter == 10) { 
     clearInterval(timer); 
    } else { 
     let wait = 200 + (Math.floor(8 * Math.random()) * 100); 
     log("waiting " + wait + "ms"); 
     let stopWaiting = Date.now() + wait; 
     while (Date.now() < stopWaiting) { 
      // busy wait 
     } 
     log("exiting callback after " + (Date.now() - start) + "ms"); 
     timeAtEndOfLastExecution = Date.now(); 
    } 
} 
timer = setInterval(tick, 200); 

そして(ノードV6.2.2付き)サンプル実行:

 
1468396730618: tick 
1468396730619: waiting 400ms 
1468396731020: exiting callback after 416ms 
1468396731637: tick (617ms) 
1468396731637: waiting 500ms 
1468396732137: exiting callback after 500ms 
1468396732837: tick (700ms) 
1468396732837: waiting 900ms 
1468396733737: exiting callback after 900ms 
1468396734837: tick (1100ms) 
1468396734837: waiting 300ms 
1468396735137: exiting callback after 300ms 
1468396735637: tick (500ms) 
1468396735637: waiting 700ms 
1468396736337: exiting callback after 700ms 
1468396737237: tick (900ms) 
1468396737237: waiting 800ms 
1468396738037: exiting callback after 800ms 
1468396739036: tick (999ms) 
1468396739036: waiting 900ms 
1468396739936: exiting callback after 900ms 
1468396741036: tick (1100ms) 
1468396741036: waiting 700ms 
1468396741736: exiting callback after 700ms 
1468396742636: tick (900ms) 
1468396742636: waiting 200ms 
1468396742836: exiting callback after 200ms 
1468396743236: tick (400ms) 

我々が見ることができるように、それは一貫して以前の反復の長さを待っているプラ​​ス私が与えた間隔:

  • 最初のコールバックは合計416msでした。次が返された後に617msが開始された
  • 2番目のコールバックには500msがかかりました。次が戻ってから700ms後に開始
  • 第3のコールバック900ms;次のコードは返されてから1100ms後に開始されます。
+0

なぜnodejsとブラウザの結果が違うのですか?なぜnodejsが実行時間をもう一度待ってから遅れて、次の繰り返ししか実行しないのでしょうか? – ufk

+1

@ufk:NodeJSとブラウザは異なる環境です。 'setInterval'はJavaScriptの一部ではないことに注意してください。これは、コードが実行されている環境の機能です。 'setInterval'が動作する正確な方法は(現在)[ブラウザに指定されています](https://www.w3.org/TR/html5/webappapis.html#timer-initialization-steps)ですが、NodeJSは必須ではありません同じように動作します。 –

+0

ok ..すべてに感謝します。ただ一つの事が私には分かりません。メイン・ポストを更新しています – ufk