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