TypeScript 5.2 新特性显示资源管理 Symbol.dispose 和 using 关键字

一、安装最新版的 TypeScript

ts 复制代码
cd your_dir
pnpm init
pnpm add typescript # 当前的 ts 版本是 `5.2.2`

当然可以使用最新的 bun/deno 等运行时直接支持 typescript>

二、提案

📕ECMAScript 显示资源管理 一个在对象上执行显式资源清理的方法。由using声明和DisposableStack对象的语义调用。

三、初始化

sh 复制代码
npx tsc --init

由于 TS 需要编译成 JS 才能运行,在各大 javascript 运行时中。

四、修改配置

json 复制代码
{
  "compilerOptions": {
     "lib": ["ES2015", "DOM", "ESNext"],
  }
}

在 lib 中至少 ES2015ESNext,因为 Symbol.dispose 目前还处在 lib.esnext.dispable.d.ts 中。

五、Symbol.dispose 定义方法

ts 复制代码
{
  const getResource = () => {
    return {
      [Symbol.dispose]: () => {
        console.log('Hello World!')
      }
    }
  }
} 

🎡 Symbol.dispose 在浏览中已经能够使用。

六、Symbol.asyncDispose 定义异步方法

ts 复制代码
const getResource = () => ({
  [Symbol.asyncDispose]: async () => {
    await someAsyncFunc();
  },
});
{
  await using resource = getResource();
}

七、using 使用方法

using 是一个关键字,与 var/let/const 类似,在 c# 中也有类似的关键字 设计

ts 复制代码
{
  const getResource = () => {
    return {
      [Symbol.dispose]: () => {
        console.log('Hello World!')
      }
    }
  }
  using resource = getResource();
} 

八、作用

  • 数据库链接关闭
  • 文件句柄
  • 订阅关闭

九、替换 try-finally

ts 复制代码
import { open } from "node:fs/promises";
let filehandle;
try {
  filehandle = await open("thefile.txt", "r");
} finally {
  await filehandle?.close();
}
ts 复制代码
import { open } from "node:fs/promises";

const getFileHandle = async (path: string) => {
  const filehandle = await open(path, "r");
  return {
    filehandle,
    [Symbol.asyncDispose]: async () => {
      await filehandle.close();
    },
  };
};
{
  await using file = getFileHandle("thefile.txt"); // 离开此作用域之后自动调用 close
}

getFileHandle 函数打开文件,getFileHandle 且返回了 [Symbol.asyncDispose], 配合 using 关键使用,解决了 try-finally 层级的代码。代码的创建与销毁的逻辑放在了 getFileHandle 函数内部,更加符合函数时编程的范式。

十、在类中使用

  • 全局的 DisposableAsyncDisposable 异步版本。
ts 复制代码
class MyResouse implements Disposable {
  #name = 'a';
  #path = '/';
  constructor(name: string, path: string) {
    this.#name = name;
    this.#path = path;
  }

  clear(name, path) {
    // your clear logic
  }

  [Symbol.dispose]() {
    this.clear(this.#name, this.#path)
  }
}
  • 使用
ts 复制代码
 {
    using file = new TempFile("lucy", "/list/lucky");

    // use file...

    if (someCondition()) {
        // do some more work...
        return;
    }
}

十一、DisposableStack/AsyncDisposableStack

ts 复制代码
function doSomeWork() {
    const path = ".some_temp_file";
    const file = fs.openSync(path, "w+");

    using cleanup = new DisposableStack();
    cleanup.defer(() => {
        fs.closeSync(file);
        fs.unlinkSync(path);
    });

    // use file...

    if (someCondition()) {
        // do some more work...
        return;
    }

    // ...
}

在这里,该defer()方法只接受一个回调,并且该回调将在cleanup被处理后运行。这样做的好处是不在需要函数的返回值了。

十二、错误处理

ts 复制代码
class ErrorA extends Error {
    name = "ErrorA";
}
class ErrorB extends Error {
    name = "ErrorB";
}

function throwy(id: string) {
    return {
        [Symbol.dispose]() {
            throw new ErrorA(`Error from ${id}`);
        }
    };
}

function func() {
    using a = throwy("a");
    throw new ErrorB("oops!")
}

try {
    func();
}
catch (e: any) {
    console.log(e.name); // SuppressedError
    console.log(e.message); // An error was suppressed during disposal.

    console.log(e.error.name); // ErrorA
    console.log(e.error.message); // Error from a

    console.log(e.suppressed.name); // ErrorB
    console.log(e.suppressed.message); // oops!
}

using声明应该能够应对异常;如果抛出错误,则在处理后重新抛出。另一方面,函数体可能会按预期执行,但Symbol.dispose可能会抛出异常。在这种情况下,该异常也会被重新抛出。

但是,如果处理之前和处理期间的逻辑都抛出错误,会发生什么情况?对于这些情况,SuppressedError已作为 的新子类型引入Error。它具有一个保存suppressed最后抛出的错误的属性和一个保存error最近抛出的错误的属性。

🦀using 声明及相关更加详细的用法

十三、小结

本文主要讲解了 using 新特性 显示资源管理,在浏览中 Symbol.dispose 已经可以使用,但是在 node.js 等环境中依然不同使用,包含 using, 新特性的普及需要一定的时间和验证。

相关推荐
Jiaberrr1 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
everyStudy1 小时前
JS中判断字符串中是否包含指定字符
开发语言·前端·javascript
城南云小白1 小时前
web基础+http协议+httpd详细配置
前端·网络协议·http
前端小趴菜、1 小时前
Web Worker 简单使用
前端
web_learning_3211 小时前
信息收集常用指令
前端·搜索引擎
tabzzz2 小时前
Webpack 概念速通:从入门到掌握构建工具的精髓
前端·webpack
凡人的AI工具箱2 小时前
AI教你学Python 第11天 : 局部变量与全局变量
开发语言·人工智能·后端·python
200不是二百2 小时前
Vuex详解
前端·javascript·vue.js
滔滔不绝tao2 小时前
自动化测试常用函数
前端·css·html5
是店小二呀2 小时前
【C++】C++ STL探索:Priority Queue与仿函数的深入解析
开发语言·c++·后端