专业的编程技术博客社区

网站首页 > 博客文章 正文

TypeScript 圈疯狂!支持手撸 WebAssembly?

baijin 2024-10-17 07:55:35 博客文章 9 ℃ 0 评论

家好,很高兴又见面了,我是"高级前端?进阶?",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!

今天给大家带来的主题是 wasmati,即支持使用 JavaScript 编写底层 WebAssembly 的公开库在年初,我也确实使用 WebAssembly 将客户端应用成功移植到了 Web,这也是为什么我一直对 WebAssembly 充满好奇的原因。我甚至在头条上开了一个合集《WebAssembly 前沿技术》来专门探讨 WebAssembly ,并将持续关注 WebAssembly 的最新动态。

下面是已发布部分文章传送门(更多文章可以阅读我的头条专题):

正如大家所看到的,当我们还在迟疑是否要在日常开发中引入 WebAssembly 的时候,很多优秀的应用、工具已经开始吃 WebAssembly 的红利了,而且取得了不错的成就,这可能也是为什么各个浏览器厂商、开发者如此热衷 WebAssembly 的原因吧。

话不多说,直接进入正题!

1.什么是 wasmati

wasmati 用于从 JavaScript 编写底层 WebAssembly。本质上,wasmati 是一个用于在指令级别编写 Wasm 的 TypeScript 库,因此 API 看起来与 Webassembly 文本格式 WAT (Webassembly text format) 完全一样。

使用 wasmati 有以下几点需要重点声明:

  • 借助于 wasmati 工具开发者可以创建底层、手动优化的 Wasm 库
  • 借助 wasmati 开发者可以 JS 原生方式在应用程序中加入一些 Wasm 来加速关键代码
  • 如果想从高级语言(如 Rust 或 C)编译 Wasm 模块,那么 wasmati 并不适合

要使用 wasmati 也非常简单,只需要通过 npm 安装相应的包后直接调用即可:

import { i64, func, local } from "wasmati";

const myMultiply = func({ in: [i64, i64], out: [i64] }, ([x, y]) => {
  local.get(x); // put input x on the stack
  local.get(y); // put input y on the stack
  i64.mul(); // pop the two last values from the stack, multiply them, put the result on the stack
});

作为参考,下面是一个等效的 WAT 代码片段:

(func $myMultiply (param $x i64) (param $y i64) (result i64)
  (local.get $x)
  (local.get $y)
  i64.mul
)

2.wasmati 已支持的特性

  • 适用于所有现代浏览器、node 和 deno
  • 与 WebAssembly 对等,API 直接对应 Wasm 操作码,如 i32.add 等。支持最新 WebAssembly 规范(2.0)的所有操作码和语言功能。
  • 可读性强,使用 wasmati 具有更好的 DX
const myFunction = func({ in: [i32, i32], out: [i32] }, ([x, y]) => {
  local.get(x);
  local.get(y);
  i32.add();
  i32.const(2);
  i32.shl();
  call(otherFunction);
});

可选语法糖以减少样板程序集,如 local.get 和 i32.const:

const myFunction = func({ in: [i32, i32], out: [i32] }, ([x, y]) => {
  i32.add(x, y); // local.get(x), local.get(y) are filled in
  i32.shl($, 2); // $ is the top of the stack; i32.const(2) is filled in
  call(otherFunction);
});
// or also
const myFunction = func({ in: [i32, i32], out: [i32] }, ([x, y]) => {
  let z = i32.add(x, y);
  call(otherFunction, [i32.shl(z, 2)]);
});
  • 类型安全:比如局部变量是有类型的,指令知道输入类型:
const myFunction = func(
  { in: [i32, i32], locals: [i64], out: [i32] },
  ([x, y], [u]) => {
    i32.add(x, u); // type error: Type '"i64"' is not assignable to type '"i32"'.
  }
);
  • 很棒的调试 DX:堆栈跟踪指向代码中调用无效操作码的确切行:
Error: i32.add: Expected i32 on the stack, got i64.
    ...
    at file:///home/gregor/code/wasmati/examples/example.ts:16:9
  • 易于构建模块:只需声明 exports,dependencies 和 imports 将自动收集。模块中没有任何导出或启动函数不需要的东西。
let mem = memory({ min: 10 });

let module = Module({ exports: { myFunction, mem } });
let instance = await module.instantiate();
  • 出色的类型推断:比如导出的函数类型是从 func 定义中推断出来的:
instance.exports.myFunction;
//                 ^ (arg_0: number, arg_1: number) => number
  • 原子导入声明:导入被声明为类型及其 JS 值。抽象出与“导入声明”分开的全局“导入对象”
const consoleLog = importFunc({ in: [i32], out: [] }, (x) =>
  console.log("logging from wasm:", x)
);

const myFunction = func({ in: [i32, i32], out: [i32] }, ([x, y]) => {
  call(consoleLog, [x]);
  i32.add(x, y);
});

具有出色的可组合性和 IO:模块/函数/等的内部表示是一个可读的 JSON 对象;接近规范的类型布局(但在必要时提高可读性或 JS 人体工程学);使用 module.toBytes()、Module.fromBytes(bytes) 与 Wasm 字节码相互转换。

3.wasmati 目前暂未实现的功能

  • Wasmati build: 用于添加一个可选的构建步骤,它将一个导出模块的文件作为输入,并将其编译为一个在运行时不依赖于 wasmati 的文件。 本质上是将 Wasm 字节码硬编码为 base64 字符串,像原始文件一样正确导入实例化的所有依赖项(import),实例化模块(top-level await)并导出模块的导出。
// example.ts
let module = Module({ exports: { myFunction, mem } });

export { module as default };
// example.ts
let module = Module({ exports: { myFunction, mem } });

export { module as default };
  • 实验性 Wasm 操作码: wasmati 希望支持尚未符合规范的最近标准化或正在进行的功能提案(如本提案)中的操作码。 最终目标是在至少一个 JS 引擎中实施后立即支持提案。
  • 自定义模块部分:wasmati 希望支持创建和解析“自定义部分”,例如:名称等
  • 反编译器::wasmati 获取任何 Wasm 文件并从中创建 wasmati TS 代码用于修改、调试等
  • source maps:这样开发者就可以在 Wasm 抛出错误时查看 JS 代码
  • 可选的 JS 解释器,可以获取 DSL 代码并在 JS 中执行
  • 可以启用更灵活的调试:检查堆栈、全局/局部范围等

本文总结

本文主要和大家介绍 wasmati,即支持使用 JavaScript 编写底层 WebAssembly 的工具。相信通过本文的阅读,大家对 wasmati 会有一个初步的了解。

因为篇幅有限,关于 wasmati 的更多用法和特性文章并没有过多展开,如果有兴趣,可以在我的主页继续阅读,同时文末的参考资料提供了大量优秀文档以供学习。最后,欢迎大家点赞、评论、转发、收藏,您的支持是我不断创作的动力。

参考资料

https://github.com/zksecurity/wasmati

https://www.zksecurity.xyz/blog/posts/wasmati/

封面图地址:https://malloc.fi/typescript-bridge-javascript-webassembly

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表