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, 新特性的普及需要一定的时间和验证。

相关推荐
weixin_4365250714 分钟前
SpringBoot 单体服务集成 Zipkin 实现链路追踪
java·spring boot·后端
q***783718 分钟前
【玩转全栈】----Django制作部门管理页面
后端·python·django
不说别的就是很菜34 分钟前
【前端面试】CSS篇
前端·css·面试
by__csdn1 小时前
nvm安装部分node版本后没有npm的问题(14及以下版本)
前端·npm·node.js
Yeats_Liao1 小时前
时序数据库系列(八):InfluxDB配合Grafana可视化
数据库·后端·grafana·时序数据库
by__csdn1 小时前
Node与Npm国内最新镜像配置(淘宝镜像/清华大学镜像)
前端·npm·node.js
脸大是真的好~1 小时前
黑马JAVAWeb -Vue工程化-API风格 - 组合式API
前端·javascript·vue.js
我命由我123451 小时前
CesiumJS 案例 P35:添加图片图层(添加图片数据)
开发语言·前端·javascript·css·html·html5·js
你挚爱的强哥1 小时前
【sgMobileUploadTypeSelect】自定义组件:从底部弹出选择上传图片文件的方式【1、上传本地文件,2、拍摄上传】
前端·javascript·vue.js
Mike_jia2 小时前
Checkmate:自建监控新标杆!开源替代Zabbix的轻量级方案实战
前端