JavaScript | Web API:タイマー・スケジューリング - setTimeout

JavaScript JavaScript
スポンサーリンク

setTimeout は「◯秒後にこれやって」を予約する関数

setTimeout は、「今すぐじゃなくて、少し時間が経ってから処理を実行したいとき」に使うタイマー関数 です。

「3 秒後にメッセージを出したい」
「ボタンを押して 1 秒後に画面を切り替えたい」
「入力が止まって 500ms 経ったら検索したい」

みたいな「ちょっと待ってから実行したい」場面でよく登場します。

ポイントは、「待っている間も JavaScript 全体が止まるわけではない」 ということです。
あくまで「◯ミリ秒後にこの関数を呼んでね」と予約しておくだけです。


setTimeout の基本形と「ミリ秒」の感覚

一番シンプルな書き方

基本形はこれです。

setTimeout(実行したい関数, 待ち時間ミリ秒);
JavaScript

例えば、2 秒後にメッセージを出したいならこう。

setTimeout(() => {
  console.log("2秒経ちました");
}, 2000);
JavaScript

ここでの 2000 は「2000 ミリ秒」=「2 秒」です。
JavaScript のタイマーは、単位がミリ秒 であることを覚えておきましょう。

コールバック関数の書き方

第一引数には「あとで実行してほしい関数」を渡します。

無名関数(アロー関数)で書くのが一番よくあるパターンです。

setTimeout(() => {
  console.log("こんにちは");
}, 1000);
JavaScript

もちろん、あらかじめ関数を定義しておいて渡すこともできます。

function greet() {
  console.log("こんにちは");
}

setTimeout(greet, 1000);
JavaScript

ここで重要なのは、greet() と「呼び出してしまわない」こと です。
渡すのは「関数そのもの」であって、「関数の実行結果」ではありません。


「非同期」であることが一番大事なポイント

setTimeout は「待ってから戻る」のではない

初心者がよく誤解するのがここです。

console.log("A");

setTimeout(() => {
  console.log("B");
}, 1000);

console.log("C");
JavaScript

このコードの実行順はどうなるでしょう?

実際の出力はこうなります。

A
C
(1秒後)
B

理由はシンプルで、setTimeout

「1 秒後にこの関数を実行しておいてね」と予約するだけ
自分自身はすぐに終わって、次の行(console.log("C"))に進む

からです。

つまり、setTimeout は「待つ関数」ではなく「予約する関数」 です。
ここをちゃんと理解できると、非同期処理の感覚が一気に掴みやすくなります。

0 ミリ秒でも「すぐ」ではない

もう一つ面白い例を見てみましょう。

console.log("A");

setTimeout(() => {
  console.log("B");
}, 0);

console.log("C");
JavaScript

出力はこうなります。

A
C
B

0 を指定しても、「今すぐ」ではなく、
「今の処理が一段落したあとで実行してね」という意味になります。

これは、JavaScript の実行キュー(イベントループ)の仕組み によるものですが、
初心者としては「0 でも後回しになる」と覚えておけば十分です。


setTimeout を止める:clearTimeout

ID を受け取って、あとからキャンセルできる

setTimeout は、呼び出したときに「タイマー ID」を返します。

const id = setTimeout(() => {
  console.log("これは実行されるかも…");
}, 5000);
JavaScript

この id を使って、「やっぱり実行しないで」 とキャンセルできます。

clearTimeout(id);
JavaScript

例えば、「ボタンを押して 3 秒後に実行するけど、その前にキャンセルボタンが押されたら止めたい」というケース。

const startButton = document.querySelector("#start");
const cancelButton = document.querySelector("#cancel");

let timerId = null;

startButton.addEventListener("click", () => {
  timerId = setTimeout(() => {
    console.log("3秒経ったので実行!");
  }, 3000);
});

cancelButton.addEventListener("click", () => {
  if (timerId !== null) {
    clearTimeout(timerId);
    console.log("キャンセルしました");
  }
});
JavaScript

ここでのポイントは、

setTimeout の戻り値を変数に保存しておく
キャンセルしたいときに clearTimeout に渡す

という流れです。


setTimeout と「引数」「this」でハマりやすいところ

コールバックに引数を渡したい場合

setTimeout のコールバックに引数を渡したいとき、
こう書いてしまうと失敗します。

setTimeout(doSomething(123), 1000); // これは NG
JavaScript

これは「doSomething(123) を今すぐ実行して、その結果を渡す」になってしまいます。

正しくは、「引数付きで呼び出す関数を、さらに関数で包む」 です。

setTimeout(() => {
  doSomething(123);
}, 1000);
JavaScript

あるいは、setTimeout の第 3 引数以降に渡す方法もあります。

function doSomething(value) {
  console.log("value:", value);
}

setTimeout(doSomething, 1000, 123);
JavaScript

この書き方も覚えておくと便利です。

ループの中で setTimeout を使うときの注意(let と var)

よくある例として、ループの中でタイマーを使うケースがあります。

for (var i = 1; i <= 3; i++) {
  setTimeout(() => {
    console.log(i);
  }, i * 1000);
}
JavaScript

一見、「1, 2, 3」と 1 秒ごとに出そうに見えますが、
実際には「3, 3, 3」と出てしまいます。

理由は、var が関数スコープで、
ループが終わった時点で i が 4 になっているからです。

これを避ける一番簡単な方法は、let を使うことです。

for (let i = 1; i <= 3; i++) {
  setTimeout(() => {
    console.log(i);
  }, i * 1000);
}
JavaScript

これなら、1 秒後に 1、2 秒後に 2、3 秒後に 3 と出ます。

ここから学べるのは、

「setTimeout の中の関数は、後から実行される」
「そのときに参照される変数がどうなっているかを意識する」

ということです。


実用的な例:入力が止まってから検索する「デバウンス」

そのまま検索すると「打つたびに API 呼びまくり」になる

検索ボックスに文字を入力するたびに API を叩くと、
1 文字入力するごとにリクエストが飛んでしまいます。

「り」
「りん」
「りんご」

と打つだけで 3 回リクエスト、みたいな状態です。

これを避けるために、
「入力が止まってから 500ms 経ったら検索する」
という動きを作るのに setTimeout がよく使われます。

デバウンスの簡単な実装

const input = document.querySelector("#search");
let timerId = null;

input.addEventListener("input", () => {
  const keyword = input.value;

  if (timerId !== null) {
    clearTimeout(timerId); // 前の予約をキャンセル
  }

  timerId = setTimeout(() => {
    console.log("検索実行:", keyword);
    // ここで fetch などで検索 API を叩く
  }, 500);
});
JavaScript

ここでやっていることは、

入力があるたびに、前のタイマーをキャンセル
「最後の入力から 500ms 経ったら検索する」ように予約

という動きです。

これが「デバウンス」と呼ばれるパターンで、
setTimeout の実用的な使い方の代表例です。


初心者として setTimeout で本当に掴んでほしいこと

setTimeout は「◯ミリ秒後にこの関数を実行してね」と予約する関数
待っている間、JavaScript 全体が止まるわけではなく、処理は先に進む(非同期)
戻り値の ID を clearTimeout に渡すことで、あとからキャンセルできる
コールバックに引数を渡すときは「関数をさらに関数で包む」か、第 3 引数以降を使う
ループや変数のスコープと組み合わせるときは、「実行されるタイミングで変数がどうなっているか」を意識する

まずは、

「3 秒後にメッセージを出す」
「ボタンを押して 1 秒後に色を変える」

みたいな小さな遊びから始めてみてください。
そのうち、「入力が止まってから検索する」「一定時間後に自動で閉じるダイアログ」など、
現実の UI に直結する使い方が自然と見えてきます。

タイトルとURLをコピーしました