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

【ITニュース解説】What JavaScript using disposes after returns and exceptions: nine checks

2026年11月05日に「Dev.to」が公開したITニュース「What JavaScript using disposes after returns and exceptions: nine checks」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

JavaScriptの`using`は、スコープ終了時や例外発生時にリソースを自動で解放する。複数のリソースは逆順に解放され、解放時のエラーも適切に処理される。非同期リソースには`await using`が必要だ。エラーは`SuppressedError`で連結され、確認が重要である。ファイル操作でもこの挙動が確認された。

ITニュース解説

JavaScriptに新たに導入された using 宣言は、プログラムが外部リソースを扱う際に問題となりがちだった「クリーンアップ処理の忘れ」や「エラー時のリソースリーク」を解決するための強力な機能である。この using 宣言は、ファイル、ネットワーク接続、データベースコネクション、一時ディレクトリといった利用後に必ず解放する必要があるリソースを、コードのスコープ(処理範囲)を抜けたときに自動的にクリーンアップする仕組みを提供する。これまで開発者は、リソースを安全に管理するために try...finally ブロックを頻繁に記述する必要があったが、using 宣言はこの定型的な処理を大幅に簡素化し、より堅牢なコードを少ない記述で実現することを可能にする。

using 宣言の基本的な動作は、Symbol.dispose という特別なメソッドを持つオブジェクトをスコープ内で登録することにある。そして、そのスコープが正常に終了する場合、あるいは途中で return によって早期に終了する場合、さらには例外が throw されて終了する場合であっても、JavaScriptエンジンは登録されたオブジェクトの Symbol.dispose メソッドを自動的に呼び出し、リソースを解放する。これにより、どのような状況下でもリソースが適切にクリーンアップされることが保証される。例えば、using first = open('A'); のように書くと、open('A') が返すオブジェクトが持つ Symbol.dispose メソッドが、first が宣言されたブロックを抜けるときに実行される。複数の using 宣言が同じスコープ内に存在する場合、それらのリソースは取得された順序とは逆の順序で破棄される。つまり、最後に取得されたリソースが最初に破棄され、最初に取得されたリソースが最後に破棄される「後入れ先出し(LIFO)」の原則に従う。これは、多くのリソースが互いに依存関係を持つ場合に安全な破棄順序となるため、重要な設計上の特性である。

この using 宣言は、プログラムの実行が正常に進む場合だけでなく、予期せぬエラーが発生した場合にも効果を発揮する。例えば、using 宣言されたリソースを使用するコードの途中で例外が throw された場合、その例外が catch ブロックで捕捉されるよりも前に、using 宣言によって登録されたリソースの破棄処理が実行される。これにより、エラーによってプログラムが停止するような状況でも、開いたファイルやネットワーク接続が閉じられないままになることを防ぐことができる。しかし、リソースそのものを取得する過程でエラーが発生した場合、例えば using second = open('B'); の open('B') の呼び出し中に例外が発生した場合は、そのリソースは using 宣言によって登録される前に失敗しているため、using 宣言による自動破棄の対象とはならない。このようなケースでは、リソース取得関数自体が部分的に確保したリソースのクリーンアップ責任を負う必要がある。

さらに複雑なケースとして、本体のコードで例外が発生し、かつその後のリソース破棄処理(Symbol.dispose メソッド内)でも例外が発生することが考えられる。このような場合、JavaScriptはすべてのアクティブな using 宣言のリソース破棄を試行し続ける。そして、複数の例外が発生した場合でも、それらのエラー情報を失わないように SuppressedError という特別なエラーオブジェクトを使って管理する。具体的には、最後に発生した破棄処理でのエラーが最終的に catch ブロックで捕捉される error オブジェクトの主要なメッセージとなり、それより前に発生したエラー(本体で発生したエラーや、先行する破棄処理で発生したエラー)は、SuppressedError オブジェクトの suppressed プロパティにチェーン状に連結されて保持される。これにより、一つの catch ブロックで複数のエラー情報をすべて取得することが可能となるが、すべてのエラーメッセージを確認するためには、この suppressed チェーンをたどって検査する必要がある。単に error.message だけを見るだけでは、本体で発生した重要なエラーを見落とす可能性があるため、注意が必要である。

JavaScriptには同期的なリソースだけでなく、ネットワーク通信やファイルI/Oといった非同期的なリソースも存在する。このような非同期的なクリーンアップが必要なリソースを扱うためには、await using 宣言を利用する。await using は、Symbol.asyncDispose という非同期的な破棄メソッドを持つオブジェクトを対象とする。await using で宣言されたリソースの Symbol.asyncDispose メソッドが呼び出されると、その非同期的な破棄処理が完了するまで、JavaScriptは次の処理や他のリソースの破棄を待機する。これにより、非同期処理が完全に終了するまでスコープを安全に離れないことが保証される。重要な点として、Symbol.asyncDispose メソッドだけを持つオブジェクトを、await を付けずに通常の using 宣言で使用しようとすると TypeError が発生する。これは、同期的な using 宣言と非同期的な await using 宣言を明確に区別し、適切な方法でリソースを管理する必要があることを示している。

実際のNode.js環境での利用例として、一時ディレクトリの自動削除が挙げられる。Node.jsの node:fs モジュールには、mkdtempDisposableSync という関数が用意されている。この関数は一時ディレクトリを作成し、そのディレクトリを自動的に削除する Symbol.dispose メソッドを持つオブジェクトを返す。この mkdtempDisposableSync が返すオブジェクトを using 宣言と組み合わせることで、一時ディレクトリが作成されたスコープを抜ける際に、ディレクトリとその中身が確実に削除される。これは、プログラム実行中に一時的にファイルを作成する必要があるが、終了時には必ずクリーンアップしたいというシナリオにおいて非常に有用である。例えば、コード内で一時ディレクトリを作成し、その中にファイルを書き込み、その後に何らかのエラーが発生してプログラムが中断した場合でも、using 宣言のおかげで一時ディレクトリがディスク上に残されることなく、自動的にクリーンアップされる。ただし、using 宣言が機能するのは、渡されたオブジェクト自体が Symbol.dispose または Symbol.asyncDispose メソッドを実装している場合に限られる。単に一時ディレクトリのパスを表す文字列を using に渡しても、そのディレクトリが自動的に削除されることはないため、注意が必要だ。

この using 宣言機能は、比較的新しいJavaScriptの仕様であり、この記事の実験はNode.js 24.15.0という特定の環境で実施されている。トランスパイラやポリフィルを使用せずにこの機能を利用するには、使用するNode.jsのバージョンやブラウザ環境が対応しているかを確認する必要がある。しかし、この機能はJavaScript開発におけるリソース管理のベストプラクティスを大きく変える可能性を秘めており、開発者がより堅牢で保守しやすいコードを書くための強力なツールとなるだろう。開発者は、自身の提供するリソースオブジェクトに Symbol.dispose や Symbol.asyncDispose を適切に実装することで、この新しいリソース管理の恩恵を最大限に引き出すことが求められる。

関連コンテンツ

関連IT用語