JavaScriptタイマーについて

setTimeout()

JavaScriptコードを記述する場合、関数の`実行を遅延`させたい場合があります。

これはsetTimeoutの役割です。後で実行するコールバック関数と、後で実行する時間をミリ秒単位で表す値を指定します。

setTimeout(() => {
  // runs after 2 seconds
}, 2000);

setTimeout(() => {
  // runs after 50 milliseconds
}, 50);

この構文は新しい関数を定義します。そこで他の関数を呼び出すことも、既存の関数名とパラメータのセットを渡すこともできます。

const myFunction = (firstParam, secondParam) => {
  // do something
};

// runs after 2 seconds
setTimeout(myFunction, 2000, firstParam, secondParam);

setTimeoutはタイマーIDを返します。これは一般的には使用されませんが、このIDを保存しておいて、スケジュールされた関数の実行を削除したい場合はクリアすることができます。

const id = setTimeout(() => {
  // should run after 2 seconds
}, 2000);

// I changed my mind
clearTimeout(id);

遅延ゼロ

タイムアウトの遅延を0に指定すると、コールバック関数は現在の関数の実行後、できるだけ早く実行されます。

setTimeout(() => {
  console.log('after ');
}, 0);

console.log(' before ');

このコードは以下を出力します。

これは、CPUを集中的なタスクでブロックすることを避け、重い計算を実行している間に他の関数をスケジューラでキューに入れて実行させるのに特に役立ちます。

一部のブラウザ(IEとEdge)は、これとまったく同じ機能を実行するsetImmediate()メソッドを実装していますが、これは標準ではなく、他のブラウザでは使用できません。しかし、Node.jsでは標準関数です。

setInterval()

setIntervalsetTimeoutに似た関数ですが、違いがあります。コールバック関数を1回実行する代わりに、指定した時間間隔(ミリ秒)で永遠に実行します。

setInterval(() => {
  // runs every 2 seconds
}, 2000);

上記の関数は、clearIntervalを使用して停止するように指示しない限り、2秒ごとに実行されます。clearIntervalには、setIntervalが返したインターバルIDを渡します。

const id = setInterval(() => {
  // runs every 2 seconds
}, 2000);

clearInterval(id);

setIntervalコールバック関数内でclearIntervalを呼び出して、再度実行するか停止するかを自動的に判断させるのが一般的です。たとえば、このコードは、App.somethingIWaitの値がarrivedになるまで何かを実行します。

const interval = setInterval(() => {
  if (App.somethingIWait === 'arrived') {
    clearInterval(interval);
  }
  // otherwise do things
}, 100);

再帰的なsetTimeout

`setInterval` は、関数がいつ実行を終了したかを考慮せずに、 n ミリ秒ごとに`関数を開始`します。

関数が常に同じ時間かかる場合は、問題ありません。

setInterval working fine

たとえば、ネットワークの状態によっては、関数の`実行時間が異なる`場合があります。

setInterval varying duration

そして、`長い実行が次の実行と重複`する可能性があります。

setInterval overlapping

これを回避するには、コールバック関数の終了時に呼び出される`再帰的なsetTimeoutをスケジュール`できます。

const myFunction = () => {
  // do something

  setTimeout(myFunction, 1000);
};

setTimeout(myFunction, 1000);

このシナリオを実現するには

Recursive setTimeout

setTimeoutsetIntervalは、Timersモジュールを介してNode.jsで使用できます。

Node.jsは、setTimeout(() => {}, 0)を使用することと同じであるsetImmediate()も提供しており、主にNode.jsイベントループで動作するために使用されます。