usingを使いリソース管理(解放)を行う
JavaScriptはガベージコレクションを備えているため、スコープを外れると自動的にメモリが解放される。しかし、非メモリリソース(データベースやファイルストリームなど)を扱う場合は、明示的な解放(cleanup)をしないとリソースリークが発生してしまう。
従来のようにtry-finally句を使いコネクションの解放やストリームのクローズ処理を行う場合、忘れずに解放処理を書くことが開発者に委ねられる。そういった煩わしさを解消するためにusingが提案された。
執筆時点では、Stage 3に到達しており、TypeScript 5.2で先行実装されている。
usingの使い方
usingを使うためには、Disposable、またはAsyncDisposableインターフェースを実装する。
Disposable
// class FileStream implements Disposable
class FileStream {
#stream = null;
open() {
this.#stream = openFileStream();
return this.#stream;
}
read() {
return this.#stream.read();
}
[Symbol.dispose]() {
if (this.#stream) {
this.#stream.close();
this.#stream = null;
}
}
}
function main() {
console.log('ファイルを読み込みます');
{
using stream = new FileStream();
stream.open();
const data = stream.read();
console.log(data);
}
// ブロックスコープを抜けるとdisposeが自動で呼ばれてリソースを解放する
}
AsyncDisposable
// class Database implements AsyncDisposable
class Database {
#conn = null;
async connect() {
this.#conn = await createConnection();
return this.#conn;
}
async query(sql) {
return await this.#conn.execute(sql);
}
[Symbol.asyncDispose]() {
if (this.#conn) {
await this.#conn.close();
this.#conn = null;
}
}
}
async function main() {
console.log('データベースに接続します');
{
using conn = await new Database().connect();
const users = await conn.query('SELECT * FROM users');
console.log(users.length);
}
// ブロックスコープを抜けるとasyncDisposeが自動で呼ばれてリソースを解放する
}