Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】AbortController & AbortSignal

2025年09月23日に「Dev.to」が公開したITニュース「AbortController & AbortSignal」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

JavaScriptの`AbortController`と`AbortSignal`は、`fetch`などの非同期処理を途中でキャンセルする標準的な方法だ。コントローラーを作成し、そのシグナルを処理に渡し、不要になったら`abort`メソッドで停止できる。これにより、アプリの応答性が向上し、不要な処理を防ぐ。

出典: AbortController & AbortSignal | Dev.to公開日:

ITニュース解説

Webアプリケーションを開発していると、ネットワーク通信のように時間がかかる「非同期処理」が頻繁に発生する。ユーザーが別のページに移動したり、検索条件を素早く変更したりする際に、まだ実行中の古い処理が完了するのを待っていると、アプリケーションの動作が遅く感じられたり、不要なリソースが消費されたりすることがある。このような状況で、不要になった非同期処理を途中で中止する仕組みが必要だ。

JavaScriptには、この非同期処理をキャンセルするための標準的な方法として、「AbortController」と「AbortSignal」という機能が用意されている。AbortControllerは、非同期処理に対して「もうこの処理は不要だから止めてほしい」という中止の指示を出す「コントローラー」の役割を担う。そして、その指示を受け取るための「信号」がAbortSignalである。非同期処理を行う関数は、このAbortSignalを受け取ることで、中止の指示を感知し、適切に処理を中断できるようになる。

AbortControllerを使うには、まずnew AbortController()のように新しいインスタンスを作成する。このコントローラーが持つsignalプロパティを、キャンセルしたい非同期処理のオプションとして渡す。例えば、ネットワーク通信を行うfetch関数であれば、fetch('/api/data', { signal: controller.signal })のように指定する。そして、何らかの理由でその非同期処理をキャンセルしたくなったら、controller.abort()を呼び出す。すると、signalを受け取っていた処理は即座に中断され、AbortErrorという特殊なエラーを発生させる。AbortErrorは、処理が意図的に中止されたことを示すため、try...catchで捕捉し適切に処理する必要がある。

controller.abort()を呼び出す際には、引数としてキャンセルの理由を渡すことも可能だ。例えば、controller.abort('ユーザーがページを離れた')のように文字列やエラーオブジェクトを渡せる。このキャンセル理由は、signal.reasonプロパティを通して後から参照できるため、なぜ中止されたのかを知る手がかりとなり、デバッグや適切なエラー処理に役立つ。

AbortControllerは、fetchのような組み込み関数だけでなく、自分で作成した非同期関数にも組み込むことができる。関数をキャンセル可能にするには、その引数にsignalを受け取るように設計する。関数内部では、signal.addEventListener('abort', () => { /* 中止時の処理 */ }, { once: true })のようにイベントリスナーを登録する。これにより、中止信号が送られたときにタイマーのクリアやPromiseのリジェクトなど、適切なクリーンアップ処理を実行できる。また、呼び出し時点で既にキャンセル済みの場合(signal.abortedtrue)、即座に処理を中断すべきである。

具体的な利用例として、fetch関数でのタイムアウト設定がある。最近のJavaScript環境では、AbortSignal.timeout(ミリ秒)という便利な関数を使うことで、簡単にタイムアウトを設定できる。例えば、fetch('/slow', { signal: AbortSignal.timeout(3000) })と書けば、3秒以内に応答がなければリクエストが自動的にキャンセルされる。これにより、応答が遅いネットワークリクエストがユーザー体験を損なうのを防ぐことができる。

ReactなどのUIフレームワークでは、コンポーネントのライフサイクルと非同期処理のキャンセルが非常に重要になる。useEffectフックを利用すると、コンポーネントが画面に表示された時にAbortControllerを作成し、データ取得処理にsignalを渡す。そして、useEffectのクリーンアップ関数の中でcontroller.abort()を呼び出すことで、コンポーネントがアンマウントされる際や、依存する値が変更されて新しい処理が開始される際に、古い実行中の処理を自動的にキャンセルできる。これは、検索ボックスの入力補完など、常に最新の結果だけが必要な場面で、古いリクエストによるバグを防ぐのに有効だ。

ネットワークからデータをストリーミングで読み込むような処理においても、AbortControllerは利用できる。fetchで取得したレスポンスのボディをreaderとして扱う場合でも、res.body.getReader({ signal: c.signal })のようにsignalを渡すことで、データ読み込み操作自体を途中でキャンセルできるようになる。これにより、大量のデータを受信している最中にユーザーが操作を中断した場合でも、不要なデータ処理を停止し、システムリソースを解放できる。

複数のAbortSignalを組み合わせるユーティリティも便利だ。例えば、複数の条件に基づいて中止したい場合、複数のAbortSignalを結合し、どれか一つがキャンセルされたら全体をキャンセルするようなロジックも実装できる。これは、より複雑な非同期処理の連携において、柔軟なキャンセル戦略を立てるのに役立つだろう。

AbortControllerを使う上でいくつか注意すべき点がある。まず、キャンセルしたい非同期処理にsignalを渡し忘れないこと。次に、自作関数ではタイマーやリスナーの適切なクリーンアップを忘れないこと({ once: true }オプションの活用やclearTimeoutの呼び出し)。また、AbortError以外のエラーを無視しないこと。意図的な中断ではない真のエラーは適切に処理する必要がある。最後に、複数の独立した操作でコントローラーを使い回さないこと。意図しないキャンセルを防ぐため、原則として操作ごとに新しいAbortControllerを作成すべきである。

AbortControllerとAbortSignalは、現代のJavaScriptアプリケーションにおいて、非同期処理を効率的かつ堅牢に管理するための強力なツールである。これらを適切に活用することで、アプリケーションの応答性を高め、不要なリソースの消費を防ぎ、より快適なユーザー体験を提供できるだろう。

関連コンテンツ

関連IT用語