【JS応用|実務向け】実務で差がつく!JavaScriptのスケジューリング(setTimeout / setInterval)の正しい使い方

1. 導入:なぜスケジューリングの理解が重要なのか

Webアプリケーション開発において、特定の処理を「後で実行したい」「定期的に繰り返したい」という要件は頻出します。しかし、単に `setTimeout` や `setInterval` を使うだけでは、意図しない挙動やパフォーマンスの低下を招くことがあります。特に、非同期処理の仕組みを理解せずに実装すると、コードの可読性が落ちるだけでなく、メモリリークやUIのフリーズといった深刻な問題に繋がります。本記事では、実務レベルで知っておくべきスケジューリングの最適解を解説します。

2. 基礎知識:スケジューリングの仕組み

JavaScriptはシングルスレッドで動作します。`setTimeout` と `setInterval` は、ブラウザやNode.jsが提供するスケジューラによって管理されます。

setTimeout:指定時間経過後に、一度だけ処理を実行します。
setInterval:指定した時間間隔で、繰り返し処理を実行します。

重要な点は、これらは「指定した時間に必ず実行される」ことを保証するものではないということです。JavaScriptのイベントループの仕組みにより、現在のメインスレッドが空いて初めて実行されるため、重い処理が先行している場合は実行が遅延します。

3. 実装と解決策:setIntervalより再帰的setTimeoutが好まれる理由

実務では、単なる繰り返しには `setInterval` よりも「再帰的な `setTimeout`」が推奨されることが多々あります。理由は、処理の完了を待ってから次のスケジュールを組めるため、実行間隔を正確に制御できるからです。

`setInterval` は、前回の処理が終わっていなくても次のインターバルが来てしまうと、無理やり処理を詰め込もうとします。これにより、処理負荷が高い場合に実行間隔が崩壊するリスクがあります。

4. サンプルプログラム:安全な再帰的スケジューリング

以下は、サーバー負荷に応じて間隔を動的に調整する実用的なパターンのサンプルです。

/
  • 再帰的setTimeoutによる柔軟なスケジューリング
  • サーバーからのレスポンスに応じて待機時間を調整する例
/ let delay = 1000; // 初期遅延 function pollServer() { // 疑似的なサーバーリクエスト処理 fetch('/api/status') .then(response => { if (response.ok) { delay = 1000; // 成功時は間隔をリセット } else { delay = 2; // エラー時は間隔を倍にして負荷を逃がす(指数バックオフ) } }) .catch(() => { delay = 2; }) .finally(() => { // 処理が完了してから次のスケジュールを組む setTimeout(pollServer, delay); }); } // 実行開始 const timerId = setTimeout(pollServer, delay); // 必要に応じて停止する場合は clearTimeout(timerId) を使用

5. 応用・注意点:現場で陥りやすい罠

・関数の呼び出しミスに注意
初心者がやりがちなミスとして、`setTimeout(func(), 1000)` のように括弧をつけてしまうケースがあります。これでは関数が即座に実行され、その戻り値が `setTimeout` に渡されてしまいます。必ず `setTimeout(func, 1000)` と参照を渡しましょう。

・メモリリークとクリーンアップ
`setInterval` を使用した際、`clearInterval` を忘れると、コンポーネントが破棄された後も関数がメモリに残り続け、リークの原因になります。React等のライブラリを使用している場合は、`useEffect` のクリーンアップ関数で確実にタイマーを解除してください。

・ブラウザの最小遅延制限
ブラウザには、ネストされたタイマーに対して「最短4ms」という制約があります。`setTimeout(func, 0)` を使っても、実際には数ミリ秒の遅延が発生することを考慮して設計しましょう。

これらの特性を理解することで、より堅牢で予測可能なフロントエンド実装が可能になります。ぜひ現場のコードで意識してみてください。

タイトルとURLをコピーしました