Javascript的新能力:显式资源管理(Explicit Resource Management)

作者:重庆崽儿Brand

本文不是原文翻译

英文原文地址:JavaScript's New Superpower: Explicit Resource Management

提案地址: https://github.com/tc39/proposal-explicit-resource-management

这是一个实验性语法提案

目前该提案处于 pending stage 4 阶段

Chromium v134V8 的 v13.8 开始提供支持。

图片描述

该提案的作用

通过一种显示方法来管理资源的生命周期,这里的资源包括:内存、I/O、文件操作(file handles)、网络连接等

提案引入的内容

  • using 和 await using
  • DisposableStack 和 AsyncDisposableStack

using / await using

用法:

using x = xxx;
await using x = xxx;

使用 usingawait using 声明的变量,会在函数体、块或者模块结尾被处理,即作用域结束时自动触发 dispose 方法

要自动触发 dispose / asyncDispose 方法的前提是要自己实现 dispose / asyncDispose 方法

提案之前的代码 VS 提案之后的代码

基础代码:

// 同步资源
class SyncResource {
  constructor(name) {
    this.name = name;
    console.log(`打开资源: ${name}`);
  }

  use() {
    console.log(`使用资源: ${this.name}`);
  }

  [Symbol.dispose]() {
    console.log(`释放资源: ${this.name}`);
  }
}

// 异步资源
class AsyncResource {
  constructor(name) {
    this.name = name;
  }

  static async open(name) {
    console.log(`异步打开资源: ${name}`);
    await new Promise(r => setTimeout(r, 100));
    return new AsyncResource(name);
  }

  async use() {
    console.log(`异步使用资源: ${this.name}`);
  }

  async [Symbol.asyncDispose]() {
    console.log(`异步释放资源: ${this.name}`);
    await new Promise(r => setTimeout(r, 100));
  }
}

新提案之前

function withoutUsing() {
  const res = new SyncResource("Logger");
  try {
    res.use();
  } finally {
    res[Symbol.dispose]();
  }
}

async function withoutAwaitUsing() {
  const res = await AsyncResource.open("DB");
  try {
    await res.use();
  } finally {
    await res[Symbol.asyncDispose]();
  }
}

提案之后


function withUsing() {
  using res = new SyncResource("Logger");
  res.use();
}
// 自动调用 res[Symbol.dispose](),即使出错也能释放

在作用域结束时自动释放资源,避免了忘记手动释放

DisposableStack / AsyncDisposableStack

  • 用于手动管理多个资源的释放顺序;
  • 遵循栈结构,注册的资源后进先出(LIFO);
  • 这两个对象提供一系列方法,比如use()adopt()defer()

使用示例:

function exampleUsingStack() {
  const stack = new DisposableStack();
  const file = {
    name: "log.txt",
    [Symbol.dispose]() {
      console.log(`关闭文件 ${this.name}`);
    }
  };
  const db = {
    name: "local.db",
    [Symbol.dispose]() {
      console.log(`关闭数据库 ${this.name}`);
    }
  };
  stack.use(file); // 注册 file 的释放
  stack.use(db);   // 注册 db 的释放
  
  stack.dispose(); // 自动依序调用 db → file 的释放逻辑
}
exampleUsingStack()
async function exampleAsyncStack() {
  const stack = new AsyncDisposableStack();

  const conn = {
    name: "async-db",
    async [Symbol.asyncDispose]() {
      console.log(`关闭异步连接 ${this.name}`);
    }
  };

  const tmpFile = {
    name: "temp.txt",
    async [Symbol.asyncDispose]() {
      console.log(`删除临时文件 ${this.name}`);
    }
  };

  stack.use(conn);
  stack.use(tmpFile);

  await stack.dispose(); // 顺序释放资源(tmpFile → conn)
}

await exampleAsyncStack();

感谢你的阅读

文章归类于: 学习笔记

文章标签: #Javascript

版权声明: 自由转载-署名-非商用