fetch を中止するのは少し面倒です。思い出してください、fetch は promise を返します。そして、JavaScript には一般的に promise を “中止する” という概念はありません。では、どうやって fetch をキャンセルしましょう?
このような目的のための、特別な組み込みのオブジェクトがあります。: AbortController.
使い方はとても簡単です:
-
Step 1: コントローラを作成します:
let controller = new AbortController();コントローラは非常にシンプルなオブジェクトです。単一のメソッド
abort()と、単一のプロパティsignalを持っています。abort()が呼ばれると、abortイベントがcontroller.signalで発生します。:このようになります:
let controller = new AbortController(); let signal = controller.signal; // controller.abort() が呼ばれるとトリガーします signal.addEventListener('abort', () => alert("abort!")); controller.abort(); // abort! alert(signal.aborted); // true (abort 後) -
Step 2:
signalプロパティをfetchオプションに渡します:let controller = new AbortController(); fetch(url, { signal: controller.signal });これで
fetchは signal をリッスンします。 -
Step 3: 中止するために
controller.abort()を呼びます:controller.abort();これで終わりです:
fetchはsignalからのイベントを得て、リクエストを中止します。
fetch が中止されたとき、その promise は AbortError という名前のエラーで reject されます。なので、次のように処理できます:
// 1秒で中止 let controller = new AbortController(); setTimeout(() => controller.abort(), 1000); try { let response = await fetch('/article/fetch-abort/demo/hang', { signal: controller.signal }); } catch(err) { if (err.name == 'AbortError') { // abort() を処理 alert("Aborted!"); } else { throw err; } } AbortController はスケーラブルで, 複数の fetch を一度にキャンセルすることができます。
例えばここでは、平行して複数の urls を fetch し、コントローラはそれらすべてを中止します。:
let urls = [...]; // 平行して fetch する url のリスト let controller = new AbortController(); let fetchJobs = urls.map(url => fetch(url, { signal: controller.signal })); let results = await Promise.all(fetchJobs); // 他の場所から: // controller.abort() ですべての fetch を停止します もし fetch とは別の独自のジョブがある場合も、一つの AbortController を使用して fetch と一緒にそれらを停止することができます。
let urls = [...]; let controller = new AbortController(); let ourJob = new Promise((resolve, reject) => { ... controller.signal.addEventListener('abort', reject); }); let fetchJobs = urls.map(url => fetch(url, { signal: controller.signal })); let results = await Promise.all([...fetchJobs, ourJob]); // 他の場所から: // controller.abort() ですべての fetch と独自のジョブを停止します
コメント
<code>タグを使ってください。複数行の場合は<pre>を、10行を超える場合にはサンドボックスを使ってください(plnkr, JSBin, codepen…)。