1. はじめに
JavaScriptの応用トピックとして、タイマー処理について学びました。具体的には setInterval()・clearInterval()・setTimeout()・clearTimeout() の使い方と、再帰関数を使った繰り返し処理の実装までを学習しています。
教材はプログラミング学習サービスの動画レッスンです。日付操作など基礎的な内容を一通り終えた後の応用トピックとして取り組みました。
2. タイマー命令の概要
JavaScriptには処理の実行タイミングを制御する命令が2種類用意されています。用途が異なるため、最初に整理しておきます。
| 命令 | 動作 |
|---|---|
| setInterval(関数, 時間) | 指定した時間ごとに処理を繰り返す |
| setTimeout(関数, 時間) | 指定した時間後に一度だけ処理を実行する |
時間はどちらも ミリ秒 で指定します。1秒 = 1000ミリ秒です。
setInterval() の最初の実行は、ページ読み込みの直後ではなく、指定時間が経過した後になります。読み込み直後から表示したい場合は、setInterval() の前に同じ処理を一度書いておくとよいようです。
3. setInterval() の使い方
setInterval() を使って、1秒ごとに現在時刻を表示するコードを書いてみます。
// 1秒(1000ミリ秒)ごとに現在時刻を表示する
setInterval(() => {
console.log(new Date());
}, 1000);
3.1 clearInterval() でタイマーを止める
繰り返しを途中で止めたいときは clearInterval() を使います。引数には、止めたいタイマーの IDを渡す 必要があります。
このIDは setInterval() の戻り値として取得できます。
以下は3から0までカウントダウンして止まるタイマーの例です。
let count = 3;
// setInterval() の戻り値をIDとして保持しておく
const intervalID = setInterval(() => {
console.log(count);
count--;
// countがマイナスになったらタイマーを止める
if (count < 0) {
clearInterval(intervalID);
}
}, 1000);
clearInterval() に渡すIDは、必ず対応する setInterval() の戻り値を使う必要があります。ブラウザがIDを 1 から連番で割り当てるとは限らないため、clearInterval(1) のようなハードコードは避けましょう。
3.2 setInterval() の実行順序
setInterval() を書いた後のコードがどのタイミングで実行されるか確認しておきます。
タイマーの登録自体は一瞬で終わるため、その後に書いたコードはすぐ実行されます。
// setInterval() が返すIDを変数に格納する
const intervalID = setInterval(() => {
console.log("1秒ごとに実行");
}, 1000);
// タイマー登録の直後(待たずに)すぐ実行される
console.log(`intervalID: ${intervalID}`); // → 出力: intervalID: 1(ブラウザ依存)
4. setTimeout() の使い方
setTimeout() は、指定した時間後に一度だけ処理を実行します。
ECサイトで時間差でクーポンを表示するような場面で使われるようです。
// ページ読み込みから3秒後に一度だけ実行される
setTimeout(() => {
console.log("50% OFF!");
}, 3000);
// タイマー登録直後にすぐ実行される
console.log("Page loaded");
別のページへリダイレクトする処理も同様に書けます。
// 3秒後に指定URLへ移動する
setTimeout(() => {
window.location.href = "https://example.com";
}, 3000);
4.1 setTimeout() で繰り返し処理を実装する
setTimeout() をネストすることで、繰り返し処理を書くことができます。
// 1秒後に実行し、その中でさらに1秒後の処理を設定する
setTimeout(() => {
console.log(new Date());
// 上の処理が終わった後、さらに1秒後に実行する
setTimeout(() => {
console.log(new Date());
// さらにもう1秒後
setTimeout(() => {
console.log(new Date());
}, 1000);
}, 1000);
}, 1000);
ただし、これを続けるとコードが長くなってしまいます。そこで再帰関数を使うことでシンプルに書けます。
4.2 再帰関数を使った書き換え
再帰関数とは、関数の中からその関数自身を呼び出す関数のことです。
// showClock を定義する(再帰関数)
function showClock() {
setTimeout(() => {
console.log(new Date());
// 処理の最後で自分自身を再び呼び出す
showClock();
}, 1000);
}
// 最初の一回だけ手動で呼び出す
showClock();
再帰関数は処理の流れが永遠に続くため、頭の中で追うのが難しいトピックです。現時点では「こういう書き方もある」という認識で問題ないと思います。
4.3 clearTimeout() でタイマーを止める
再帰関数で書いた setTimeout() を途中で止めるには clearTimeout() を使います。
ボタンをクリックしたら時計を止める例です。
const pElement = document.querySelector("p");
const buttonElement = document.querySelector("button");
// タイマーIDを格納する変数(再代入が必要なのでletで宣言)
let timeoutID;
function showClock() {
// タイマーIDを変数に代入する(毎回上書きされる)
timeoutID = setTimeout(() => {
pElement.textContent = new Date();
// 1秒後に自分自身を再び呼び出す
showClock();
}, 1000);
}
showClock();
// ボタンをクリックしたら直近のタイマーをキャンセルする
buttonElement.addEventListener("click", () => {
clearTimeout(timeoutID);
});
timeoutID は showClock() が呼ばれるたびに新しいIDで上書きされます。そのため const ではなく let で宣言する必要があります。
5. setInterval() と setTimeout() の違い
setInterval() と再帰 setTimeout() は、どちらも繰り返し処理に使えますが、実行タイミングの計算起点が異なります。
| 種類 | タイミングの起点 |
|---|---|
| setInterval | 前の処理の開始時点から計測する |
| 再帰 setTimeout | 前の処理の終了時点から計測する |
setInterval() は前の処理の開始時点から次の実行タイミングを計測するため、処理に時間がかかると処理が重なってしまう可能性があります。
一方、再帰 setTimeout() は処理が終わってから次の実行を待つため、処理が重なることなくブラウザへの負荷を抑えられます。
複雑な処理を繰り返し実行したい場合は、再帰 setTimeout() の方がブラウザへの負荷を抑えやすいようです。単純なUIの更新程度であれば、シンプルな setInterval() で十分だと思います。
まとめ
今回学んだタイマー処理のポイントを整理します。
-
setInterval()は一定間隔で繰り返し処理を実行する。止めるときはclearInterval()を使う -
setTimeout()は指定時間後に一度だけ処理を実行する。止めるときはclearTimeout()を使う - どちらも時間は ミリ秒 で指定し、登録後はすぐ次の処理に進む
- タイマーを止めるには戻り値のIDを変数に保持しておき、それを
clearInterval()/clearTimeout()に渡す -
setTimeout()を再帰関数と組み合わせるとsetInterval()のような繰り返し処理が書けるが、処理が重なりにくいというメリットがある
タイマーIDの管理まわり( const と let の使い分けなど)は少し混乱しましたが、コードを書きながら整理できました。引き続きJavaScriptの応用トピックを進めていきます。