setTimeout は指定した時間が経過した後に関数を 1 回だけ実行するタイマー関数です。通知の自動消去、遅延リダイレクト、API リトライ、デバウンスなど、「一定時間待ってから実行する」操作の基本となるメソッドです。
この記事でわかること
・setTimeout の基本構文と戻り値
・clearTimeout でタイマーをキャンセルする方法
・delay 0 の仕組みとイベントループの関係
・setTimeout を Promise 化して async/await で使う方法(sleep 関数)
・デバウンス(入力の待ち合わせ)パターン
・通知の自動消去・遅延リダイレクト・API リトライの実務パターン
・setInterval との使い分け
・setTimeout の基本構文と戻り値
・clearTimeout でタイマーをキャンセルする方法
・delay 0 の仕組みとイベントループの関係
・setTimeout を Promise 化して async/await で使う方法(sleep 関数)
・デバウンス(入力の待ち合わせ)パターン
・通知の自動消去・遅延リダイレクト・API リトライの実務パターン
・setInterval との使い分け
setTimeout の基本構文
構文
const timerId = setTimeout(callback, delay, arg1, arg2, ...); // callback: 遅延後に実行する関数 // delay: 遅延時間(ミリ秒)。1000 = 1秒。省略すると 0 // arg1...: callback に渡す引数(省略可) // 戻り値: タイマーID(clearTimeout で取り消しに使う)
基本例
// 2秒後にメッセージを表示
setTimeout(() => {
console.log("2秒が経過しました");
}, 2000);
引数を渡す
function greet(name, greeting) {
console.log(`${greeting}, ${name}!`);
}
// 1.5秒後に greet("田中", "こんにちは") を実行
setTimeout(greet, 1500, "田中", "こんにちは");
// → "こんにちは, 田中!"
第 1 引数に文字列を渡さないでください。
setTimeout("alert(1)", 1000) は eval と同じように文字列を評価するため、XSS の原因になります。必ず関数(アロー関数・関数参照)を渡しましょう。clearTimeout でタイマーをキャンセルする
setTimeout の戻り値(タイマー ID)を clearTimeout に渡すと、まだ実行されていないタイマーをキャンセルできます。
JavaScript
const timerId = setTimeout(() => {
console.log("この処理は実行されません");
}, 3000);
// 実行前にキャンセル
clearTimeout(timerId);
ボタンクリックでキャンセルする例
const timerId = setTimeout(() => {
window.location.href = "/next-page";
}, 5000);
document.getElementById("cancelBtn").addEventListener("click", () => {
clearTimeout(timerId);
console.log("リダイレクトをキャンセルしました");
});
既に実行済みのタイマーに clearTimeout を呼んでもエラーにはなりません。安全に呼び出せるため、念のため clearTimeout するパターンは問題ありません。
delay 0 の仕組み(イベントループ)
setTimeout(fn, 0) は「0ms 後に実行」ではなく、現在の同期処理がすべて完了した後、次のイベントループで実行するという意味です。
JavaScript
console.log("1: 同期処理 開始");
setTimeout(() => {
console.log("3: setTimeout(0) の中");
}, 0);
console.log("2: 同期処理 終了");
// 出力順序:
// "1: 同期処理 開始"
// "2: 同期処理 終了"
// "3: setTimeout(0) の中"
この仕組みを図解すると次のようになります。
| フェーズ | 実行される処理 |
|---|---|
| 同期処理 | console.log("1") → setTimeout を登録 → console.log("2") |
| コールスタックが空になる | — |
| タスクキュー | setTimeout のコールバックが実行される → console.log("3") |
delay 0 の実用的な使い方
DOM 更新後に処理を実行する
// innerHTML の変更は同期だが、ブラウザの描画は非同期
element.innerHTML = "<p>新しいコンテンツ</p>";
// setTimeout(0) でブラウザが描画する余地を作る
setTimeout(() => {
// ここでは新しいコンテンツが画面に表示されている
element.querySelector("p").classList.add("fade-in");
}, 0);
ブラウザの最低遅延は約 4ms です。
setTimeout(fn, 0) でも実際には 4ms 程度の遅延があります。ネストが深くなると(5 段階以上)最低 4ms が保証されます。setTimeout を Promise 化する(sleep 関数)
setTimeout は async/await と直接組み合わせられません。Promise でラップした sleep 関数を作ると、非同期処理の中で「N ミリ秒待つ」を直感的に書けます。
sleep 関数
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 使用例
async function main() {
console.log("開始");
await sleep(2000); // 2秒待つ
console.log("2秒後");
await sleep(1000); // さらに1秒待つ
console.log("合計3秒後");
}
main();
キャンセル可能な sleep
function cancellableSleep(ms) {
let timerId;
const promise = new Promise((resolve, reject) => {
timerId = setTimeout(resolve, ms);
});
promise.cancel = () => clearTimeout(timerId);
return promise;
}
// 使用例
const wait = cancellableSleep(5000);
// 途中でキャンセル
wait.cancel();
デバウンス(入力の待ち合わせ)
デバウンスは「最後のイベントから一定時間経過するまで処理を遅らせる」テクニックで、setTimeout と clearTimeout の組み合わせで実装します。検索フォームのリアルタイム検索やウィンドウリサイズの処理に使います。
JavaScript
function debounce(fn, delay) {
let timerId;
return function (...args) {
clearTimeout(timerId);
timerId = setTimeout(() => fn.apply(this, args), delay);
};
}
// 使用例: 入力が止まって300ms後に検索を実行
const searchInput = document.getElementById("search");
const debouncedSearch = debounce((query) => {
console.log("検索:", query);
// fetch(`/api/search?q=${query}`) ...
}, 300);
searchInput.addEventListener("input", (e) => {
debouncedSearch(e.target.value);
});
キー入力のたびに clearTimeout で前のタイマーをキャンセルし、新しいタイマーをセットすることで、入力が止まってから 300ms 後に 1 回だけ検索を実行します。
デバウンスの対義語がスロットル(一定間隔に 1 回だけ実行)です。スクロールイベントにはスロットル、入力イベントにはデバウンスが適しています。
setInterval との使い分け
| 比較項目 | setTimeout | setInterval |
|---|---|---|
| 実行回数 | 1 回だけ | 繰り返し実行 |
| 停止 | clearTimeout(id) |
clearInterval(id) |
| 繰り返し実行 | 再帰呼び出しで実現 | 自動で繰り返し |
| 非同期処理との相性 | 良い(完了を待てる) | 悪い(実行が積み重なる可能性) |
setTimeout の再帰で繰り返し実行
function repeat() {
console.log("実行:", new Date().toLocaleTimeString());
setTimeout(repeat, 1000); // 完了後に次をスケジュール
}
repeat();
詳しくは「setInterval の使い方」で setInterval と setTimeout 再帰の違いを比較しています。
実務でよく使うパターン
通知メッセージの自動消去
JavaScript
function showNotification(message, duration = 3000) {
const el = document.createElement("div");
el.className = "notification";
el.textContent = message;
document.body.appendChild(el);
setTimeout(() => {
el.style.opacity = "0";
el.addEventListener("transitionend", () => el.remove());
}, duration);
}
showNotification("保存しました", 2000);
遅延リダイレクト(キャンセル可能)
JavaScript
const msg = document.getElementById("redirect-msg");
let seconds = 5;
msg.textContent = `${seconds}秒後にリダイレクトします...`;
const countdownId = setInterval(() => {
seconds--;
msg.textContent = `${seconds}秒後にリダイレクトします...`;
if (seconds <= 0) clearInterval(countdownId);
}, 1000);
const redirectId = setTimeout(() => {
window.location.href = "/dashboard";
}, 5000);
// キャンセルボタン
document.getElementById("cancelBtn").addEventListener("click", () => {
clearTimeout(redirectId);
clearInterval(countdownId);
msg.textContent = "リダイレクトをキャンセルしました";
});
API リトライ(指数バックオフ)
JavaScript
async function fetchWithRetry(url, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const res = await fetch(url);
if (res.ok) return await res.json();
throw new Error(`HTTP ${res.status}`);
} catch (error) {
console.error(`試行 ${attempt + 1} 失敗:`, error.message);
if (attempt < maxRetries - 1) {
// 指数バックオフ: 1秒 → 2秒 → 4秒
const delay = Math.pow(2, attempt) * 1000;
console.log(`${delay}ms 後にリトライ...`);
await new Promise(r => setTimeout(r, delay));
}
}
}
throw new Error(`${maxRetries}回リトライしましたが失敗しました`);
}
this の問題とアロー関数
JavaScript
class Timer {
constructor() {
this.count = 0;
}
start() {
// NG: 通常関数では this が変わる
// setTimeout(function() { this.count++; }, 1000);
// OK: アロー関数で this を保持
setTimeout(() => {
this.count++;
console.log(this.count); // 1
}, 1000);
}
}
new Timer().start();
関連記事
- setInterval の使い方 — 一定間隔で繰り返し実行
- カウントダウンタイマーの作成
- ハンバーガーメニューの実装方法 — CSS アニメーション
- ページ上部へ戻るボタンの実装方法
- アコーディオンの作り方
よくある質問
QsetTimeout(fn, 0) は本当に 0ms 後に実行されますか?
Aいいえ。ブラウザには最低約 4ms の遅延があります。また、現在の同期処理と既にキューに入っている処理がすべて完了してから実行されるため、実際の遅延は環境によって異なります。0ms は「次のイベントループサイクルで実行する」という意味です。
QsetTimeout のコールバック内で this が undefined になります。
A通常の
function を setTimeout に渡すと、this はグローバルオブジェクト(strict mode では undefined)になります。アロー関数を使えば外側の this を保持できます。setTimeout(() => this.method(), 1000)QsetTimeout を async/await で使いたいのですが。
A
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } と Promise でラップした sleep 関数を作り、await sleep(2000) のように使います。QclearTimeout を呼んでもコールバックが実行されてしまいます。
AclearTimeout はまだ実行されていないタイマーのみキャンセルできます。コールバックが既に実行中の場合はキャンセルできません。タイマーをセットした直後に clearTimeout を呼んでいるか、delay 時間が十分かを確認してください。
Qデバウンスとスロットルの違いは何ですか?
Aデバウンスは「最後のイベントから N ms 経過後に 1 回だけ実行」、スロットルは「N ms に 1 回だけ実行(間引き)」です。検索入力にはデバウンス、スクロールイベントにはスロットルが適しています。
まとめ
setTimeout は指定時間後に関数を 1 回だけ実行するタイマー関数です。
- 基本:
setTimeout(fn, delay)で delay ミリ秒後に fn を 1 回実行 - キャンセル:
clearTimeout(id)で実行前のタイマーを取り消し - delay 0: 次のイベントループサイクルで実行(DOM 更新後の処理に有用)
- Promise 化: sleep 関数で async/await と組み合わせ可能
- デバウンス: setTimeout + clearTimeout で入力の待ち合わせを実装
通知の自動消去、遅延リダイレクト、API リトライなど、「一定時間待ってから実行する」操作の基本として幅広く活用できます。繰り返し実行が必要な場合は setInterval との使い分けも押さえておきましょう。