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