【ITニュース解説】AbortController.abort(reason)をcatchした時のブラウザごとの挙動
2025年09月03日に「Qiita」が公開したITニュース「AbortController.abort(reason)をcatchした時のブラウザごとの挙動」について初心者にもわかりやすいように丁寧に解説しています。
ITニュース概要
Fetch通信を`AbortController.abort(reason)`で中断すると、エラー処理(`catch`)で受け取る内容がブラウザ間で異なる。ChromeやEdgeは中断理由(`reason`)を返す一方、Safariは`AbortError`を返す。開発者はこのブラウザ差を考慮する必要がある。
ITニュース解説
ウェブアプリケーションを開発していると、インターネット経由でデータを取り寄せる「非同期通信」という処理を頻繁に利用する。特にJavaScriptではfetchという機能を使って、サーバーから情報を取得したり、サーバーへ情報を送ったりする。このfetch処理は時間がかかる場合があり、途中でユーザーが操作をキャンセルしたり、何らかの理由で処理を中断する必要が出てきたりすることがある。例えば、検索中にユーザーが別の検索語を入力した場合、前の検索リクエストは不要になる。このようなときに役立つのがAbortControllerという機能だ。
AbortControllerは、進行中の非同期処理、特にfetchリクエストを途中でキャンセルするための仕組みである。これを使うと、不要になった通信を中断し、システムのリソース消費を抑えたり、ユーザー体験を向上させたりできる。AbortControllerはAbortSignalというオブジェクトを持っており、このAbortSignalをfetchのオプションとして渡すことで、そのfetchリクエストをAbortControllerが制御できるようになる。
通信をキャンセルしたいときは、AbortControllerが持つabort()というメソッドを呼び出す。このabort()メソッドには、キャンセル理由を示すための引数としてreasonを渡すことができる。例えば、abort('ユーザーがキャンセルしました')のように文字列を渡したり、もっと詳しい情報を持つオブジェクトを渡したりすることも可能だ。このreasonは、開発者が後でなぜキャンセルされたのかを特定し、それに応じた処理を行うために使われることを期待されている。
fetchのような非同期処理は、その結果がすぐに返るわけではないため、Promiseという形で未来の結果を約束するオブジェクトを返す。処理が成功した場合はその結果が、失敗した場合はエラーがPromiseを通じて伝えられる。エラーが発生した場合や処理が中断された場合、開発者はPromiseのcatchブロックを使ってそのエラーを受け取り、適切な対応を記述する。AbortControllerでabort()が実行されたときも、fetchによって返されたPromiseはエラーとなり、catchブロックが実行される。
ここで、ブラウザによってcatchで受け取るエラーの内容に違いがあることが今回のテーマである。具体的には、Google ChromeやMicrosoft Edgeの場合、AbortController.abort(reason)で指定したreason引数が、そのままcatch(err)のerrとして受け取れる。つまり、開発者が指定したキャンセル理由が直接エラーハンドリングのコードで利用できるため、例えば「ユーザーキャンセル」なのか「タイムアウト」なのかといった、より詳細なキャンセル理由に基づいて処理を分岐させることができる。これは非常に便利で、エラーの原因究明やユーザーへのきめ細やかなフィードバックに役立つ。
一方、Apple Safariの場合、abort(reason)が実行されても、catch(err)で受け取るerrは、AbortErrorという名前の標準的なエラーオブジェクトになる。このAbortErrorオブジェクト自体は、確かに処理がキャンセルされたことを示しているのだが、AbortController.abort()に渡したreasonの中身は含まれない。つまり、Safariではキャンセルはされたとわかるものの、なぜキャンセルされたのか(reasonの内容)をcatchブロック内で直接知ることはできないのだ。
このブラウザごとの挙動の違いは、ウェブアプリケーションを開発する上で重要な問題となる。開発者は、あらゆるユーザーがどのブラウザを使っても同じようにアプリケーションが動作する「ブラウザ互換性」を常に考慮しなければならない。もしChrome/Edgeの挙動にだけ依存して、catchブロックでerrの中身を直接reasonとして利用するコードを書いてしまうと、Safariユーザーの環境では意図した通りに動作しない、あるいはエラーハンドリングが適切に行われないという問題が発生する。
この問題に対処するためには、catchブロック内で受け取ったエラーオブジェクトの「種類」を判別するのが一般的な方法だ。JavaScriptのエラーオブジェクトには、そのエラーの種類を示すnameというプロパティがある。キャンセルによって発生したエラーであれば、そのnameは必ずAbortErrorになる。
したがって、開発者は以下のように対応できる。catch(err)ブロックの中で、まずerr.nameが'AbortError'であるかどうかを確認する。もし'AbortError'であれば、それはキャンセルによって発生したエラーだと判断できる。その上で、Chrome/Edgeのようにreasonを直接利用したい場合は、errオブジェクトがAbortErrorではない、つまりreasonそのものである場合にだけerrの内容を読み取るようにする、といった条件分岐の実装が考えられる。しかし、もっと堅実な方法は、Safariでも通用するように、キャンセル理由をcatchブロック内で直接利用することに頼らず、AbortControllerを生成した側で別途、キャンセル理由となる情報を管理する仕組みを導入することである。例えば、キャンセル時にグローバルな状態変数に理由を保存し、catchブロックからはその状態変数を参照するといった方法だ。
今回のAbortController.abort(reason)におけるブラウザごとの挙動の違いは、一見すると些細な点に思えるかもしれないが、安定したウェブアプリケーションを開発するためには、このような細かな仕様の違いにも目を配り、適切に対応していく必要があることを示している。特に、これからシステムエンジニアを目指す人にとっては、ブラウザ間の互換性を意識し、標準的なエラー処理の作法を理解することが、高品質なソフトウェアを開発するための第一歩となるだろう。
文字数: 1968文字