≪ Today I learned. RSS購読
公開日
タグ
JavaScript
著者
ダーシノ

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が自動で呼ばれてリソースを解放する
}