AbortSignal.timeout()でfetchに数行でタイムアウトを付ける(Node.js/ブラウザ共通)

fetch には既定のタイムアウトが無い。相手が応答を返さないと、その待ちは(TCP側のタイムアウトまで)延々と続く。従来は AbortControllersetTimeout を手で組み合わせていたが、いまは AbortSignal.timeout() で数行にできる。Node.js(18以降)とモダンブラウザの両方で使える。

以前のやり方(手書き)

1
2
3
4
5
6
7
8
9
async function fetchOld(url, ms = 5000) {
const ctrl = new AbortController();
const id = setTimeout(() => ctrl.abort(), ms);
try {
return await fetch(url, { signal: ctrl.signal });
} finally {
clearTimeout(id); // 後始末を忘れるとタイマーが残る
}
}

動くが、clearTimeout の後始末が要る。忘れるとプロセスが余計に生き続けることがある。

いまのやり方:AbortSignal.timeout()

1
2
3
async function fetchWithTimeout(url, ms = 5000) {
return fetch(url, { signal: AbortSignal.timeout(ms) });
}

これだけ。AbortSignal.timeout(ms) は「ms経過後に自動でabortするsignal」を返す。タイマーの後始末も内部でやってくれる。タイムアウトすると TimeoutErrorname === "TimeoutError"DOMException)で reject される。

1
2
3
4
5
6
7
8
9
10
try {
const res = await fetchWithTimeout("https://example.com/slow", 3000);
const text = await res.text();
} catch (e) {
if (e.name === "TimeoutError") {
console.error("3秒でタイムアウトしました");
} else {
throw e;
}
}

タイムアウトと「ユーザーによるキャンセル」を両立する

「タイムアウト」も付けたいし「ユーザーの中止ボタン」でも止めたい、というときは AbortSignal.any() で複数のsignalを合成する。どれか1つが発火したら中止になる。

1
2
3
4
5
6
7
8
9
10
function fetchCancelable(url, { ms = 5000, userSignal } = {}) {
const signals = [AbortSignal.timeout(ms)];
if (userSignal) signals.push(userSignal);
return fetch(url, { signal: AbortSignal.any(signals) });
}

// 使う側
const ctrl = new AbortController();
button.onclick = () => ctrl.abort(); // ユーザーが中止
const res = await fetchCancelable("/api/data", { ms: 8000, userSignal: ctrl.signal });

中止理由で分岐したいときは signal.reason を見る。AbortSignal.timeout() 由来なら TimeoutErrorcontroller.abort(reason) なら渡した reason が入る。

注意点

  • タイムアウトはヘッダ受信までではなく、fetchのabortが効く範囲res.body を後からゆっくり読む場合、本文読み取り中の停止は別途 signal を効かせる必要がある(res.text() はabortで中断される)。
  • リトライと組み合わせるなら、タイムアウトごとに新しい AbortSignal.timeout() を作る(signalは使い捨て)。
  • Node.jsは18以降で AbortSignal.timeout / any が使える。古い環境向けには手書き版をフォールバックに。

まとめ

fetch のタイムアウトは、いまや AbortSignal.timeout(ms)signal に渡すだけで済む。ユーザーキャンセルと併用したいときは AbortSignal.any() で合成する。AbortController + setTimeout + clearTimeout の定型を書いていたなら、後始末込みで数行に減らせる。


AbortSignal.timeout()でfetchに数行でタイムアウトを付ける(Node.js/ブラウザ共通)
https://blog.hashito.biz/2026/07/18/abortsignal-timeout-fetch-timeout-node-browser/
著者
hashito
作成日
2026年7月18日
著作権