導入: なぜsetIntervalの理解が重要なのか
Web開発において、定期的に処理を実行したい場面は非常に多くあります。例えば、カウントダウンタイマーや、リアルタイムで更新される株価表示などです。しかし、JavaScriptのsetIntervalを安易に使うと、ブラウザの負荷増大やメモリリークを引き起こす可能性があります。この記事では、setIntervalの基礎から、現場で推奨されるより安全な代替案までを解説します。
基礎知識: setIntervalとJavaScriptの非同期処理
setIntervalは、指定したミリ秒間隔で繰り返し処理を実行する関数です。仕組みとしては、ブラウザの「タイマーイベント」に処理を登録する形になります。
注意すべき点は、JavaScriptが「シングルスレッド」で動作していることです。もし間隔内に処理が完了しなかった場合、処理が積み重なってしまい、画面のフリーズや意図しない動作を招くことがあります。これが「非同期処理」におけるsetIntervalの最大の課題です。
実装/解決策: setTimeoutによる再帰的な呼び出し
現場で推奨される手法は、setIntervalを使わずにsetTimeoutを再帰的に呼び出す方法です。これには以下のメリットがあります。
1. 前回の処理が終わってから次のタイマーをセットするため、処理が重なってもフリーズしない。
2. 状況に応じて(処理結果によって)実行間隔を動的に変更できる。
3. 処理を停止させたいタイミングを細かく制御できる。
サンプルプログラム: 安全なタイマー実装
以下は、非同期処理を考慮した安全なタイマーの実装例です。
// 実行するかどうかを管理するフラグ
let isRunning = true;
// 繰り返し処理の関数
const tick = async () => {
if (!isRunning) return;
try {
// ここでAPI呼び出しなどの非同期処理を実行する想定
console.log("処理を実行中...");
// 処理が重い場合を想定した擬似的な待機
await new Promise(resolve => setTimeout(resolve, 1000));
} catch (error) {
console.error("エラーが発生しました", error);
} finally {
// 処理が終わった後に、次のタイマーを予約する(再帰)
// これにより、処理が重なっても前の完了を待ってから次が走る
if (isRunning) {
setTimeout(tick, 2000); // 2秒の間隔を空けて再実行
}
}
};
// タイマー開始
tick();
// タイマーを止める場合はisRunningをfalseにする
// isRunning = false;
応用・注意点: 現場で役立つアドバイス
現場で最も注意すべきは「クリーンアップ処理」です。Reactなどのフレームワークを使用している場合、コンポーネントがアンマウントされた後もタイマーが動き続けると、存在しないDOMを操作しようとしてエラーが発生します。
必ずタイマーのIDを管理するか、上記のようにフラグを使って「コンポーネントが不要になったら処理を中断する」というロジックを組み込むようにしましょう。また、ブラウザがバックグラウンドに回るとタイマーの精度が落ちる(スロットリングされる)仕様があることも、設計時には忘れないようにしてください。