AbortController
を使うことで実現できる。
MDNにも書いてあるけど、以下の操作でfetch APIによるHTTPリクエストを中断できる。
fetch()
の第2引数のオブジェクトのsignal
フィールドにAbortController.signal
を渡すAbortController.abort()
を呼ぶ
HTTPリクエストが中断されると、 fetch()
が返すPromiseはrejectされる。
ユーザー操作でリクエストを中断する
MDNのサンプルコードやデモを参照。
タイムアウトさせる
window.setTimeout()
のコールバック関数内で AbortController.abort()
を呼ぶとできる。
タイムアウトを過ぎなかったときのために window.clearTimeout()
しているけど、いらないかもしれない。
const invokeAPI = async (url) => { const controller = new AbortController(); const timer = window.setTimeout(() => { controller.abort(); }, 1000); const response = await fetch(url, { signal: controller.signal, }); window.clearTimeout(timer); return resp; };
Promise.race()
でタイムアウトさせる場合との違い
Promise.race()
で fetch()
とタイムアウトさせるPromiseを並走させてもタイムアウトは実現できそうに見える。
const timeout = (msec) => { return new Promise((_, reject) => { window.setTimeout(() => reject('timeout'), msec); }); }; await Promise.race([fetch(...), timeout(1000)]);
たしかにタイムアウトできているように見えるけど、AbortControllerを使った場合と違ってHTTPリクエスト自体はキャンセルされない。
一方axiosでは
cancel tokenという仕組みでHTTPリクエストをキャンセルできる。また、リクエストに対してタイムアウトを設定できる。
cancel tokenはcancelable PromiseというECMAScriptのproposalに基づいて実装されたらしいけど、このproposalは取り下げられた。Promiseをキャンセルしたいという欲求がありそう。