js中的using声明

一、using 声明简介

usingECMAScript 2023(ES14) 引入的一项新语法,用于自动管理资源的生命周期

它的主要目标是简化"资源使用完后自动释放"的场景,例如文件句柄、数据库连接、锁等。 相关提案可见:github.com/tc39/propos...

📜 语法结构:

csharp 复制代码
using 变量名 = 表达式;
await using 变量名 = 异步表达式;

using 声明的变量必须是一个实现了 Symbol.disposeSymbol.asyncDispose 方法的对象。

当作用域退出(无论是正常返回还是异常)时,JS 引擎会自动调用该方法释放资源。


二、基本使用示例

同步版本

javascript 复制代码
class File {
  constructor(name) {
    this.name = name;
    console.log(`打开文件: ${name}`);
  }
  [Symbol.dispose]() {
    console.log(`关闭文件: ${this.name}`);
  }
}

function main() {
  using f = new File("data.txt");
  console.log("读取文件中...");
}

main();
// 输出:
// 打开文件: data.txt
// 读取文件中...
// 关闭文件: data.txt

⚡ 当 main() 执行完毕时,f 离开作用域,系统会自动调用 f[Symbol.dispose]()


异步版本

javascript 复制代码
class AsyncResource {
  async [Symbol.asyncDispose]() {
    console.log("异步释放资源...");
    await new Promise(res => setTimeout(res, 1000));
    console.log("资源已释放");
  }
}

async function run() {
  await using r = new AsyncResource();
  console.log("使用异步资源中...");
}

run();

三、内部机制简析

  • using词法作用域绑定 (和 let/const 类似)。

  • 离开作用域时:

    • 如果是同步资源 → 调用 [Symbol.dispose]()
    • 如果是异步资源 → 调用 [Symbol.asyncDispose]()
  • 它可以和 trycatchfinally 一起安全使用。


四、使用场景

场景 传统做法 新写法(using)
文件操作 try/finally 手动关闭 自动调用 dispose
数据库连接 手动断开 自动释放连接
临时锁 try/finally 释放锁 离开作用域自动释放

五、注意事项

  1. using 只能在模块或函数作用域中使用,不能在全局作用域直接声明。
  2. 不能与 var 共用。
  3. 不会影响 GC(垃圾回收),它只是提供结构化释放资源的机制。

六、实践demo------简化revokeObjectURL

在图片回显/文件下载等场景中,开发很容易忘记revokeObjectURL,我们可以利用using特性进行封装,消除revokeObjectURL的心智负担。

就比如上传图片后回显的操作:

js 复制代码
console.log('🚀 using demo 启动...');

function objectURLResource(blob) {
    const url = URL.createObjectURL(blob);
    console.log('🆕 创建 URL:', url);
    return {
        url,
          [Symbol.dispose]() {
            console.log("释放资源...");
            URL.revokeObjectURL(url);
            console.log('🧹 自动释放 URL:', url);
            
        },
        // [Symbol.dispose]() {
        //     console.log("释放资源...");
        //     new Promise(resolve => setTimeout(resolve, 1000)).then(()=>{
        //         URL.revokeObjectURL(url);
        //         console.log('🧹 自动释放 URL:', url);
        //     })
            
        // },
          async [Symbol.asyncDispose]() {
            console.log("异步释放资源...");
            await new Promise(resolve => setTimeout(resolve, 3000)); // 模拟异步操作
            URL.revokeObjectURL(url);
            console.log('🧹 自动释放 URL:', url);
        },
    };
}



async function showImage(blob) {
    // await using resource = objectURLResource(blob);
    using resource = objectURLResource(blob);
    const img = document.createElement('img');
    img.src = resource.url;
    img.alt = 'demo';
    const { resolve, promise } = Promise.withResolvers()
    img.onload = () => {
        resolve()
    }
    document.body.appendChild(img);
    await promise;
    console.log('✅ 演示完毕,URL 将被自动 revoke');
}
document.querySelector('#file').addEventListener('change',async (e) => {
    const f = e.target.files[0]
   await showImage(f);
   console.log('do others...    ')

})

revokeObjectURL的注意事项

当img加载后,执行revokeObjectURL并不会影响内容显示,但如果img未加载完就执行了revokeObjectURL,则无法显示图片。因此以上demo中增加了await promise的处理,确保图片被显示出来。

那么可能会有人问,此处能否用Symbol.asyncDispose来解决该问题?答案是不能。但这是一个很好的问题,触及到了 Symbol.asyncDisposeSymbol.dispose的根本区别.

七、Symbol.asyncDispose与Symbol.dispose的区别

表面上看,以上demo中如果写成await using resource = objectURLResource(blob);,释放资源用的是Symbol.asyncDispose,如果不加await,则调用Symbol.dispose

异步释放:

那么这两个api的使用场景分别是啥呢?我们不妨在同步释放中写下如下代码:

javascript 复制代码
[Symbol.dispose]() {
    console.log("释放资源...");
    new Promise(resolve => setTimeout(resolve, 1000)).then(()=>{
        URL.revokeObjectURL(url);
        console.log('🧹 自动释放 URL:', url);
    })
},

可以看到,do others...在释放完成前就执行了。

因此可以理解:Symbol.asyncDispose是为了让后续的代码等待异步释放完成后再执行,因为有些释放场景,可能需要进行io或其他异步校验,而Symbol.dispose释放过程是同步的,后续代码执行时可以认为资源已经被释放了。如果后续代码执行时并不关心该资源是否已经释放了,那使用Symbol.dispose即可。

相关推荐
EndingCoder3 小时前
枚举类型:常量集合的优雅管理
前端·javascript·typescript
Electrolux3 小时前
[wllama]纯前端实现大语言模型调用:在浏览器里跑 AI 是什么体验。以调用腾讯 HY-MT1.5 混元翻译模型为例
前端·aigc·ai编程
sanra1233 小时前
前端定位相关技巧
前端·vue
起名时在学Aiifox3 小时前
从零实现前端数据格式化工具:以船员经验数据展示为例
前端·vue.js·typescript·es6
oMcLin3 小时前
如何在Manjaro Linux上配置并优化Caddy Web服务器,确保高并发流量下的稳定性与安全性?
linux·服务器·前端
码途潇潇4 小时前
JavaScript 中 ==、===、Object.is 以及 null、undefined、undeclared 的区别
前端·javascript
之恒君4 小时前
Node.js 模块加载 - 4 - CJS 和 ESM 互操作避坑清单
前端·node.js
be or not to be4 小时前
CSS 背景(background)系列属性
前端·css·css3
前端snow4 小时前
在手机端做个滚动效果
前端
webkubor4 小时前
🧠 2025:AI 写代码越来越强,但我的项目返工却更多了
前端·机器学习·ai编程