👋

JavaScriptのタイマーまとめ【setInterval / setTimeout】

に公開4

setInterval()

指定した時間間隔ごとに処理を繰り返す

setInterval(() => {
  console.log('1秒ごとに実行');
}, 1000);

使う場面:時計の表示、アニメーション処理、定期的なチェックなど。

setTimeout()

指定した時間後に一度だけ処理を実行。

setTimeout(() => {
  console.log('3秒後に実行');
}, 3000);

使う場面:一定時間後に処理をしたいとき(例:モーダルを閉じる、アラート表示など)

カウントダウンの実装例

let count = 10;
const timerId = setInterval(() => {
  console.log(count);
  count--;
  if (count < 0) {
    clearInterval(timerId);
    console.log('終了!');
  }
}, 1000);

clearInterval() で止めるのがポイント!

clearInterval()

setInterval() の処理を止めるときに使う。

const id = setInterval(() => console.log('動作中'), 500);
setTimeout(() => clearInterval(id), 3000); // 3秒後に停止

setTimeout()の中でsetTimeout()を使う(再帰タイマー)

function showTime() {
  console.log(new Date().toLocaleTimeString());
  setTimeout(showTime, 1000); // 自分自身を再び呼び出す
}
showTime();

これで「setInterval()」と同じような動きを再現できる。
ただし setTimeout() を使うことで、処理が重くてもズレにくいというメリットがある!

再帰関数とは?

関数の中で自分自身を呼び出す関数。
上の showTime() のように、setTimeout(showTime, 1000) で自分を再度呼んでいるのが「再帰処理」。
一見難しそうだけど、「自分でループを作る」イメージ。

setInterval() と setTimeout() の違い

比較項目 setInterval() setTimeout()
実行回数 繰り返し実行 1回だけ
処理のズレ 起こりやすい 起こりにくい
停止方法 clearInterval() clearTimeout()
適した用途 定期的な監視 正確な繰り返し・タイミング調整

setTimeout() を使うメリット

  • 処理が正確な間隔で動く(遅延してもズレにくい)
  • タイマーの制御が柔軟
  • async/await と組み合わせやすい

clearTimeout()

setTimeout() を止めるときに使う。

const id = setTimeout(() => console.log('動くはずだった!'), 5000);
clearTimeout(id); // → 実行されない

タイマーを「止める」「再開する」実装例

main.js
{
  const pElement = document.querySelector('p');
  const startButton = document.querySelector('.start');
  const stopButton = document.querySelector('.stop');
  let timeoutId;
  let isRunning = false;

  function showClock() {
    pElement.textContent = new Date().toLocaleTimeString();
    timeoutId = setTimeout(showClock, 1000); // 再帰的に呼ぶ
  }

  startButton.addEventListener('click', () => {
    if (!isRunning) {
      isRunning = true;
      showClock();
    }
  });

  stopButton.addEventListener('click', () => {
    clearTimeout(timeoutId);
    isRunning = false;
  });
}
html
<p></p>
<button class="start">スタート</button>
<button class="stop">ストップ</button>

まとめ

用語 意味 停止方法
setInterval() 一定間隔で繰り返し clearInterval()
setTimeout() 一定時間後に1回だけ clearTimeout()
再帰 + setTimeout ズレの少ない繰り返し clearTimeout()
Date() 現在の日時を取得 -

Discussion

dameyodamedamedameyodamedame

setTimeout()が「ズレの少ない繰り返し」とありますが、以下のコードを見てください。

let start = performance.now();
const log = (s)=>{
    const t = Math.floor(performance.now() - start);
    console.log(`${s}: ${t}[ms]`);
};

// setIntervalで1秒置きに10回
const COUNT = 10;
let countInterval = 0;
const INTERVAL = 1000;
const timerId = setInterval(()=>{
    log('interval');
    if (++countInterval == COUNT) clearInterval(timerId);
}, INTERVAL);

// setTimeoutで1秒置きに10回
let countTimeout = 0;
const callback = ()=>{
    log('timeout');
    if (++countTimeout <= COUNT) setTimeout(callback, INTERVAL);
};
if (++countTimeout <= COUNT) setTimeout(callback, INTERVAL);

// 1.1秒のビジーループ
while (performance.now() - start < 1100);

実行するとこんな感じになります。

interval: 1100[ms]
timeout: 1104[ms]
interval: 2100[ms]
timeout: 2116[ms]
interval: 3104[ms]
timeout: 3120[ms]
interval: 4108[ms]
timeout: 4124[ms]
interval: 5113[ms]
timeout: 5129[ms]
interval: 6121[ms]
timeout: 6137[ms]
interval: 7129[ms]
timeout: 7144[ms]
interval: 8134[ms]
timeout: 8150[ms]
interval: 9142[ms]
timeout: 9158[ms]
interval: 10152[ms]
timeout: 10168[ms]

setTimeout()でもズレは同じに見えます。

このコードを以下のように変更すると…

let start = performance.now();
const log = (s)=>{
    const t = Math.floor(performance.now() - start);
    console.log(`${s}: ${t}[ms]`);
};

// setIntervalで1秒置きに10回
const COUNT = 10;
let countInterval = 0;
const INTERVAL = 1000;
const timerId = setInterval(()=>{
    log('interval');
    if (++countInterval == COUNT) clearInterval(timerId);
}, INTERVAL);

// setTimeoutで1秒置きに10回(ただし経過時間に合わせて調整する)
let countTimeout = 0;
const callback = ()=>{
    log('timeout');
    if (++countTimeout <= COUNT) setTimeout(callback, INTERVAL * countTimeout + start - performance.now());
};
if (++countTimeout <= COUNT) setTimeout(callback, INTERVAL * countTimeout + start - performance.now());

// 1.1秒のビジーループ
while (performance.now() - start < 1100);

実行結果は以下のようになります。

timeout: 1100[ms]
interval: 1105[ms]
timeout: 1999[ms]
interval: 2107[ms]
timeout: 3001[ms]
interval: 3109[ms]
timeout: 4000[ms]
interval: 4112[ms]
timeout: 5009[ms]
interval: 5118[ms]
timeout: 6002[ms]
interval: 6128[ms]
timeout: 7005[ms]
interval: 7130[ms]
timeout: 8012[ms]
interval: 8137[ms]
timeout: 9001[ms]
interval: 9142[ms]
timeout: 10002[ms]
interval: 10144[ms]

つまり、setTimeoutはタイムアウトまでの時間を毎回自分で調整できるというだけの話で、精度の違いがあるわけではありません。毎回自分で調整していないコードで「ズレが少ない」という説明をすると、おかしな感じがしてしまいます。

1
へみおへみお

ご指摘ありがとうございます!
確かに、「ズレが少ない」という説明は少しズレた説明になってしまいました。
すごく勉強になります!
もっと精度の良い記事を載せれるようにこれから精進していきます!

junerjuner

処理が正確な間隔で動く

タスクキューへの登録タイミング自体は setTimeout と同じ精度なので 他のキューにより実行タイミング自体は普通にずれる可能性があることに注意が必要です。
登録であれば是ですが実行であるなら否です。

https://developer.mozilla.org/ja/docs/Web/API/HTML_DOM_API/Microtask_guide#タスクとマイクロタスク

へみおへみお

再度ご指摘ありがとうございます。
JavaScriptまだまだ細かい部分は勉強中ですのでご教示していただけて嬉しいです!
これからもよろしくお願いいたします🙇‍♂️

1