ECMAScript 2026에서 가장 주목받는 새로운 기능 중 하나인 Explicit Resource Management가 도입됩니다. C#의 using문, Python의 with문과 유사하게, JavaScript에서도 using 키워드를 통해 리소스의 자동 정리(disposal)를 안전하게 처리할 수 있게 되었습니다. 파일 핸들, 데이터베이스 연결, 네트워크 소켓 등 명시적 해제가 필요한 리소스를 다룰 때 메모리 누수와 리소스 누수를 방지하는 데 핵심적인 역할을 합니다.

기존 리소스 관리의 문제점

기존 JavaScript에서는 try-finally 패턴으로 리소스를 정리해야 했습니다. 이 방식은 코드가 장황해지고 실수로 정리 코드를 빠뜨리기 쉽습니다.

// 기존 방식: try-finally로 리소스 정리
async function readFile() {
  const handle = await fs.promises.open('data.txt', 'r');
  try {
    const content = await handle.readFile('utf-8');
    return content;
  } finally {
    await handle.close(); // 반드시 수동으로 닫아야 함
  }
}

// 여러 리소스를 다루면 중첩이 깊어짐
async function copyFile(src, dest) {
  const srcHandle = await fs.promises.open(src, 'r');
  try {
    const destHandle = await fs.promises.open(dest, 'w');
    try {
      const data = await srcHandle.readFile();
      await destHandle.writeFile(data);
    } finally {
      await destHandle.close();
    }
  } finally {
    await srcHandle.close();
  }
}

using 키워드 기본 사용법

using 키워드는 Symbol.dispose 메서드를 구현한 객체에 대해 블록 스코프를 벗어날 때 자동으로 dispose를 호출합니다.

// Symbol.dispose를 구현한 리소스 클래스
class DatabaseConnection {
  #connection;

  constructor(config) {
    this.#connection = createConnection(config);
    console.log('DB 연결 생성');
  }

  query(sql) {
    return this.#connection.execute(sql);
  }

  [Symbol.dispose]() {
    this.#connection.close();
    console.log('DB 연결 해제');
  }
}

// using 키워드로 자동 리소스 관리
function getUserData(userId) {
  using db = new DatabaseConnection({ host: 'localhost' });
  // 블록 끝에서 자동으로 db[Symbol.dispose]() 호출
  const result = db.query(`SELECT * FROM users WHERE id = ${userId}`);
  return result;
}
// 함수 종료 시 자동으로 "DB 연결 해제" 출력

await using으로 비동기 리소스 관리

네트워크 연결이나 파일 핸들처럼 비동기적으로 정리해야 하는 리소스에는 await using을 사용합니다.

class AsyncFileHandle {
  #handle;

  static async open(path, mode) {
    const instance = new AsyncFileHandle();
    instance.#handle = await fs.promises.open(path, mode);
    return instance;
  }

  async read() {
    return await this.#handle.readFile('utf-8');
  }

  async write(data) {
    await this.#handle.writeFile(data);
  }

  // 비동기 dispose
  async [Symbol.asyncDispose]() {
    await this.#handle.close();
    console.log('파일 핸들 비동기 해제');
  }
}

// await using으로 비동기 정리
async function processFile() {
  await using file = await AsyncFileHandle.open('data.json', 'r');
  const content = await file.read();
  const parsed = JSON.parse(content);
  return parsed;
  // 함수 종료 시 await file[Symbol.asyncDispose]() 자동 호출
}

DisposableStack과 AsyncDisposableStack

여러 리소스를 그룹으로 관리해야 할 때 DisposableStack을 활용합니다. 스택에 추가된 리소스는 LIFO(후입선출) 순서로 정리됩니다.

function createServerResources() {
  using stack = new DisposableStack();

  const db = stack.use(new DatabaseConnection({ host: 'localhost' }));
  const cache = stack.use(new RedisClient({ port: 6379 }));
  const logger = stack.use(new FileLogger('/var/log/app.log'));

  // 에러가 발생해도 logger -> cache -> db 순서로 정리
  return { db, cache, logger };
}

// 비동기 버전
async function createAsyncResources() {
  await using stack = new AsyncDisposableStack();

  const ws = stack.use(await WebSocket.connect('wss://api.example.com'));
  const stream = stack.use(await createReadStream('/data/large.csv'));

  // 블록 종료 시 stream -> ws 순서로 비동기 정리
  return processData(ws, stream);
}

실전 활용: Express 미들웨어에서의 사용

// Express 라우트에서 DB 트랜잭션 관리
app.post('/api/transfer', async (req, res) => {
  await using tx = await db.beginTransaction();

  try {
    await tx.query('UPDATE accounts SET balance = balance - ? WHERE id = ?',
      [req.body.amount, req.body.fromId]);
    await tx.query('UPDATE accounts SET balance = balance + ? WHERE id = ?',
      [req.body.amount, req.body.toId]);
    await tx.commit();
    res.json({ success: true });
  } catch (err) {
    await tx.rollback();
    res.status(500).json({ error: err.message });
  }
  // tx가 commit/rollback 안 됐으면 자동으로 rollback 후 연결 해제
});

브라우저 및 런타임 지원 현황

2026년 4월 기준, using 키워드는 Chrome 127+, Firefox 132+, Safari 18.2+에서 지원됩니다. Node.js는 22 LTS부터, Deno는 1.46+, Bun은 1.1.20+에서 사용 가능합니다. TypeScript는 5.2부터 이미 지원하고 있어, TypeScript 프로젝트에서는 즉시 활용할 수 있습니다.

Explicit Resource Management는 JavaScript의 리소스 안전성을 한 단계 끌어올리는 기능입니다. 특히 서버 사이드 Node.js 개발에서 데이터베이스 연결, 파일 핸들, 네트워크 소켓 등을 다룰 때 반드시 활용해야 할 패턴입니다.