setTimeout() / setInterval() — 後で動かす

0 ミリ秒を指定しても、いま動いている処理が終わるまで動きません。止め方、引数の渡し方、 var で書いたループが全部同じ値になる理由、待つ関数の作り方まで実行して確かめます。

実行して検証済み処理系Node 22.22.3対応ES2015難易度●●○○○目安9更新

0 を指定しても、すぐには動きません。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
同期 -> timeout
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
1 いますぐ 2 いますぐ 3 マイクロタスク 4 タイマー

指定するのは「この時間で動く」ではなく、 この時間が経ったら順番待ちに並ぶという意味です。

いま動いている処理が終わるまで、順番は回ってきません。

これは言語ではなく実行環境の仕組み(HTML Standard)ですが、Node にも同じものが入っています。

動く順番

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
終わり
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
引数: 1 2
何が動くか
1 いま書いてある処理(同期)
2 Promise の続き(マイクロタスク
3 setTimeout で預けたもの(タスク

Promise のほうが必ず先です。 0 を指定しても変わりません。 → Promise — then / catch / finally と async / await

止める

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
前 後
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
3

setTimeout() の返り値を取っておいて、clearTimeout() に渡します。

返り値の中身は環境によって違います。 ブラウザでは数値、Node では別の値です。 中身を見たり、比べたり、保存したりしないでください。 渡すだけにします。

引数を渡す

javascript
const out = [];

for (var i = 0; i < 3; i++) {
setTimeout(() => out.push(i), 0);
}

await new Promise((resolve) => setTimeout(resolve, 20));

console.log(out.join(' '));
3 3 3
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
0 1 2

第3引数から後ろが、そのまま関数に渡ります。 閉包で渡せるので、いまはあまり使いません。

待つ関数を作る

javascript
try {
setTimeout(() => {
throw new Error('中で落ちた');
}, 0);
} catch (error) {
// ここには来ない
}
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
中で捕まえた: 中で落ちた

この3行が、非同期の待ち時間でいちばんよく使う形です。 再試行の間隔を空けるときにも使います。 → 失敗したら再試行する

setInterval() — 繰り返す

止めるまで動き続けます。 clearInterval() を必ず書いてください。

中の処理が指定した間隔より長いと、溜まっていきます。 通信のように時間の読めない処理を繰り返すなら、 setTimeout() を終わるたびに掛け直すほうが安全です。

よくある間違い

var で書いたループ

全部 3 になりました。 var はループ全体で1つしかないので、実際に動くころには 3 になっています。

let なら、繰り返しごとに別の入れ物になります。

スコープと閉包 — 変数はどこから見えるか

try で囲んでも捕まらない

try を抜けたずっと後に動くので、この catch は無関係です。 実際に走らせると捕まらないまま外へ出てしまうので、このページでは実行例にできません。

囲むのは中側です。

Error と try / catch / finally / throw

指定した時間ちょうどに動くと思う

指定できるのは最短の待ち時間だけです。

  • いま動いている処理が終わるまで待たされます
  • 画面が裏に回っていると、間隔が延ばされることがあります
  • 入れ子にしたタイマーには、下限が設けられています

時間の計測や、正確な間隔が要る処理には使えません。

まとめ

  • 0 を指定してもいまの処理が終わってから動く
  • 順番は 同期 → Promise → タイマー
  • 返り値は clearTimeout() に渡すだけ。中身は環境で違う
  • sleepnew Promise と組にして作る
  • setInterval()止めるまで動く。時間の読めない処理には向かない
  • var のループは全部同じ値になる。let を使う
  • 外側の try では捕まえられない。 中で囲む
  • 指定できるのは最短の待ち時間だけ

この記事の根拠

  1. Timers — HTML Standard (WHATWG)html.spec.whatwg.org
  2. Jobs and Host Operations — ECMAScript® 2026 Language Specificationtc39.es
  3. setTimeout() — MDNdeveloper.mozilla.org

掲載しているコード例は、公開前に読み手が押したときに動くのと同じもので実行して出力を突き合わせています。結果はリポジトリに残しています。

このページの原文(Markdown)