使用 Deno 的一流 Wasm 支持
Back to Top
为了覆盖更广泛的受众,这篇文章已从日语翻译而来。
您可以在这里找到原始版本。
简介
#在 11 月的 Deno 2.1 版本中,加入了 First-class Wasm support 功能。
Deno 2.1: Wasm Imports and other enhancements
在以往的 Deno 中,可以使用 Web 标准的 API 加载和运行 Wasm,但从 2.1 之后,可以像普通模块一样,通过 import 使用 Wasm。
Wasm 的加载与运行:传统方法
#以下是实例化本地的 WebAssembly 文件 add.wasm
并调用其公开的函数(add)的示例。
const wasmInstance = await WebAssembly.instantiateStreaming(
fetch(new URL("./add.wasm", import.meta.url)));
const { add } = wasmInstance.instance.exports as { add: (a: number, b: number) => number };
console.log(add(1, 2));
(虽然此处为了避免 TypeScript 的类型错误做了处理,)代码显得相当冗长。首先,需要通过 WebAssembly API 进行实例化,然后从实例中获取导出的函数(这里是 add)以供使用。
运行时需要使用 --allow-read 权限[1]。
$ deno --allow-read main.ts
3
上述的 add.wasm
是通过以下的 wat 文件转换而成的。
(module
(func (export "add") (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add))
可以通过安装 WABT(WebAssembly Binary Toolkit)并使用 wat2wasm
命令,将此 wat 文件转换为 wasm 格式。
如果使用 wat2wasm
的演示网站,即使不在本地安装 WABT,也可以直接下载转换后的 Wasm 文件。
关于加载与运行 Wasm 的 Web 标准 API,请参考以下文档:
加载和运行 WebAssembly 代码 - WebAssembly | MDN
有关在 Deno 中通过 Web 标准 API 使用 Wasm 的示例,可以参考以下文章。这是一篇比较早的内容。
Wasm 的加载与运行:import
#从 Deno 2.1 开始,可以通过 import 加载和运行 Wasm。
import { add } from "./add.wasm";
console.log(add(1, 2));
代码变得非常简洁。运行也同样简单:
deno main.ts
Deno 也会对 Wasm 模块进行类型检查。
从 Web Worker 使用
#在以前的连载文章中,曾介绍过利用 Web Worker 分布式执行 Wasm 代码的示例。当时的方法是,在主进程中预先编译 Wasm 并传递给 Worker,然后在 Worker 中实例化并执行。但现在,可以直接在 Worker 的代码中进行 import,使操作更加简便[2]。
以下是 Worker 的代码。通过 add
模块,根据接收到的消息中的参数执行加法,并发送结果。
import { add } from "./add.wasm";
self.onmessage = e => {
const result = add(e.data.a, e.data.b); // 执行 add
postMessage(self.name + ": " + result); // 发送 Worker 名称和结果
};
以下是主进程的代码。创建多个 Worker 并注册接收消息的处理程序。
const worker1 = createWorker("worker1");
const worker2 = createWorker("worker2");
handleWorkerMessage(worker1); // 注册 worker1 的消息接收处理程序
handleWorkerMessage(worker2); // 注册 worker2 的消息接收处理程序
worker1.postMessage({ a: 1, b: 2 }); // 向 worker1 发送消息
worker2.postMessage({ a: 3, b: 4 }); // 向 worker2 发送消息
function createWorker(name: string) {
const worker = new Worker(new URL("./worker.ts", import.meta.url).href, {
type: "module",
name: name
});
return worker;
}
function handleWorkerMessage(worker: Worker) {
worker.onmessage = e => {
console.log(e.data);
};
}
运行结果。可以从每个 Worker 获取使用 Wasm 执行的计算结果。
$ deno --allow-read main.ts
worker1: 3
worker2: 7
总结
#以上是对 Deno 一流 Wasm 支持的简单测试。由于 Wasm 被纳入了 Deno 的模块图,因此 Deno 可以对其进行解析和缓存,从而实现更快速的加载和使用。
作为一流支持的特性,显然已经完全省去了原本类似“胶水代码”的部分。使用 Wasm 的门槛大大降低了。