【JavaScript】setInterval の使い方|一定間隔で繰り返し実行・clearInterval で停止・setTimeout との違い・実務パターンまで解説

setInterval一定の時間間隔で関数を繰り返し実行するためのタイマー関数です。カウントダウンタイマー、リアルタイム時計、自動スライドショー、API のポーリングなど、定期実行が必要な場面で幅広く使われます。

この記事でわかること
・setInterval の基本構文と戻り値
・clearInterval でタイマーを停止する方法
・実行回数を制限する方法
・setTimeout の再帰呼び出しとの違い
・バックグラウンドタブでの挙動
・メモリリーク防止のクリーンアップ
・カウントダウン・時計・スライドショー・ポーリングの実務パターン
スポンサーリンク

setInterval の基本構文

構文
const intervalId = setInterval(callback, delay, arg1, arg2, ...);
// callback: 繰り返し実行する関数
// delay:    実行間隔(ミリ秒)。1000 = 1秒
// arg1...:  callback に渡す引数(省略可)
// 戻り値:   タイマーID(clearInterval で停止に使う)
基本例(1秒ごとにカウントアップ)
let count = 0;

const intervalId = setInterval(() => {
  count++;
  console.log(count);
}, 1000);

// 出力: 1, 2, 3, 4, 5, ...(1秒ごと)
delay に 0 を指定しても即座には実行されません。ブラウザは最低約 4ms の間隔を保証します。また、最初の実行は delay ミリ秒後です(即座ではありません)。

clearInterval でタイマーを停止する

setInterval は clearInterval で明示的に停止するまで永久に繰り返されます。不要になったタイマーは必ず停止しましょう。

JavaScript
let count = 0;

const intervalId = setInterval(() => {
  count++;
  console.log(count);

  // 5回実行したら停止
  if (count >= 5) {
    clearInterval(intervalId);
    console.log("停止しました");
  }
}, 1000);

// 出力: 1, 2, 3, 4, 5, "停止しました"

ボタンで開始・停止を制御する

JavaScript
let intervalId = null;

document.getElementById("startBtn").addEventListener("click", () => {
  // 二重起動を防止
  if (intervalId !== null) return;

  intervalId = setInterval(() => {
    console.log("実行中:", new Date().toLocaleTimeString());
  }, 1000);
});

document.getElementById("stopBtn").addEventListener("click", () => {
  clearInterval(intervalId);
  intervalId = null;
});
開始ボタンを複数回押すと、タイマーが重複して起動し制御不能になります。intervalId !== null のチェックで二重起動を防止してください。

setInterval と setTimeout の再帰呼び出しの違い

定期実行には setInterval のほかに、setTimeout を再帰的に呼び出す方法もあります。両者の違いを理解することが重要です。

setInterval(処理時間を含んだ間隔)
// 1秒間隔で実行(処理時間が長いと次の実行が詰まる可能性あり)
setInterval(() => {
  heavyProcess(); // 処理に300msかかる場合
}, 1000);
// 実際の間隔: 1000ms → 次の実行開始は700ms後
setTimeout 再帰(処理完了後に次をスケジュール)
function repeat() {
  heavyProcess(); // 処理に300msかかる場合
  setTimeout(repeat, 1000);
}
repeat();
// 実際の間隔: 処理300ms + 待機1000ms = 1300ms
比較項目 setInterval setTimeout 再帰
間隔のカウント 前回の開始から次の開始まで 前回の完了から次の開始まで
処理が遅い場合 実行が積み重なる可能性あり 確実に前の処理が完了してから次を実行
非同期処理 完了を待たずに次が実行される async/await と組み合わせ可能
コードの簡潔さ シンプル やや冗長
軽い処理(DOM 更新、カウンター)なら setInterval、重い処理や非同期処理(API 呼び出し)には setTimeout 再帰が安全です。

async/await と setTimeout 再帰の組み合わせ

JavaScript
async function pollApi() {
  try {
    const res = await fetch("/api/status");
    const data = await res.json();
    console.log("ステータス:", data.status);

    if (data.status !== "complete") {
      // 処理完了後に5秒後に再実行
      setTimeout(pollApi, 5000);
    }
  } catch (error) {
    console.error("エラー:", error);
    // エラー時も再試行
    setTimeout(pollApi, 10000);
  }
}

pollApi();

バックグラウンドタブでの挙動

ブラウザはバッテリーや CPU の消費を抑えるため、バックグラウンドタブでは setInterval の実行間隔を最低 1000ms に制限します(Chrome・Firefox・Safari 共通)。

状態 指定 100ms の場合 指定 2000ms の場合
フォアグラウンド 100ms 間隔で実行 2000ms 間隔で実行
バックグラウンド 1000ms に引き伸ばされる 2000ms のまま
カウントダウンタイマーなどで正確な時間を扱う場合は、setInterval の回数ではなく Date.now() で経過時間を計算するようにしましょう。バックグラウンドタブに切り替えてもタイマーがずれなくなります。

メモリリーク防止(クリーンアップ)

clearInterval を呼ばずにページ遷移やコンポーネント破棄が行われると、タイマーが残り続けてメモリリークの原因になります。

SPA(React)でのクリーンアップ

React(useEffect)
import { useEffect, useState } from "react";

function Timer() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      setCount(prev => prev + 1);
    }, 1000);

    // クリーンアップ: コンポーネント破棄時に停止
    return () => clearInterval(id);
  }, []);

  return <p>{count}秒経過</p>;
}

イベントリスナーの解除とセット

JavaScript
// ページを離れるときにタイマーを停止
let intervalId = setInterval(doSomething, 1000);

window.addEventListener("beforeunload", () => {
  clearInterval(intervalId);
});

実務でよく使うパターン

カウントダウンタイマー

JavaScript
function countdown(seconds, onTick, onComplete) {
  let remaining = seconds;
  onTick(remaining);

  const id = setInterval(() => {
    remaining--;
    onTick(remaining);

    if (remaining <= 0) {
      clearInterval(id);
      onComplete();
    }
  }, 1000);

  return id; // 外部から停止可能
}

// 使用例: 10秒カウントダウン
countdown(
  10,
  (sec) => console.log(`残り${sec}秒`),
  () => console.log("タイムアップ!")
);

リアルタイム時計

JavaScript
function startClock(elementId) {
  const el = document.getElementById(elementId);

  function update() {
    el.textContent = new Date().toLocaleTimeString("ja-JP");
  }

  update(); // 初回即時表示
  return setInterval(update, 1000);
}

const clockId = startClock("clock");
// 停止: clearInterval(clockId);

自動スライドショー

JavaScript
const slides = document.querySelectorAll(".slide");
let current = 0;

function showSlide(index) {
  slides.forEach(s => s.classList.remove("active"));
  slides[index].classList.add("active");
}

// 3秒ごとに次のスライドに切り替え
const slideInterval = setInterval(() => {
  current = (current + 1) % slides.length;
  showSlide(current);
}, 3000);

// マウスホバーで一時停止
const container = document.querySelector(".slideshow");
container.addEventListener("mouseenter", () => clearInterval(slideInterval));

API ポーリング(setTimeout 再帰版)

JavaScript
let isPolling = true;

async function pollNotifications() {
  if (!isPolling) return;

  try {
    const res = await fetch("/api/notifications");
    const data = await res.json();

    if (data.length > 0) {
      renderNotifications(data);
    }
  } catch (e) {
    console.error("通知取得エラー:", e);
  }

  // 30秒後に再実行
  setTimeout(pollNotifications, 30000);
}

pollNotifications();
// 停止: isPolling = false;

関連記事

よくある質問

QsetInterval の最初の実行を即座に行いたいのですが。
AsetInterval は最初の実行が delay ミリ秒後です。即座に実行したい場合は、コールバック関数を setInterval の前に 1 回手動で呼び出してください。update(); const id = setInterval(update, 1000);
QsetInterval と setTimeout はどちらを使うべきですか?
A軽い処理の定期実行なら setInterval(コードがシンプル)。API 呼び出しなど重い処理や非同期処理には setTimeout 再帰(前の処理完了を待ってから次を実行)が安全です。
QclearInterval を呼んだ後、同じ intervalId を再利用できますか?
AclearInterval 後に同じ ID で再度停止しても無害ですが、再開には使えません。再開するには setInterval を再度呼び出して新しい ID を取得する必要があります。
Qバックグラウンドタブに切り替えるとタイマーがずれます。
Aブラウザはバックグラウンドタブでは setInterval の間隔を最低 1000ms に制限します。正確な時間管理には setInterval の回数ではなく Date.now() で経過時間を計算するようにしましょう。
QReact で setInterval を使うと setState が反映されません。
AuseEffect のクロージャ内では state の初期値が固定されます。setCount(prev => prev + 1) のように関数形式の更新を使えば、常に最新の値に基づいて更新されます。クリーンアップ関数で clearInterval を忘れないようにしましょう。

まとめ

setInterval は一定間隔で処理を繰り返し実行するための基本的なタイマー関数です。

  • 基本: setInterval(fn, delay) で delay ミリ秒ごとに fn を実行
  • 停止: clearInterval(id) で明示的に停止(必須)
  • setTimeout との違い: setInterval は開始基準、setTimeout 再帰は完了基準の間隔
  • バックグラウンド: 最低 1000ms に制限される。正確な時間は Date.now() で計算
  • クリーンアップ: コンポーネント破棄時やページ離脱時に必ず clearInterval する

カウントダウン、時計、スライドショーなどの定期実行には setInterval が最適です。API ポーリングなど非同期処理の定期実行には setTimeout 再帰を使い分けてください。