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…)。