Rust 与 JavaScript 的 WebAssembly 互操作指南
1. Rust 中导入和导出 JS 函数
导入 JS 函数
Rust 代码中可以通过 extern
块导入 JavaScript 函数:
#[link(wasm_import_module = "mod")] // 指定 JS 模块名
extern { fn foo(); // 声明导入的 JS 函数
}
如果没有指定 wasm_import_module
,默认模块名是 "env"
。
导出 Rust 函数供 JS 调用
Rust 中使用 #[no_mangle]
和 pub extern
导出函数供 JavaScript 调用:
#[no_mangle]
pub extern fn bar() {// 函数实现
}
注意:由于 WebAssembly 支持的值类型有限,这些导入/导出的函数只能使用基础数值类型(如
i32
,f64
等)作为参数和返回值。
2. JS 端调用 Rust 导出的函数
在 JS 中加载 wasm 模块后,Rust 导出的函数可以像普通 JS 函数一样调用:
const { bar } = await WebAssembly.instantiateStreaming(fetch("module.wasm"), importObject);
bar(); // 调用 Rust 导出的函数
需要注意 wasm 实例需要提供 importObject
,其中包含 wasm 模块所需的所有导入项,包括内存(memory)和 JS 函数。
3. 复杂数据交互:超越基础数值
由于 wasm 模块与 JS 拥有独立的内存空间,复杂数据结构(如字符串、数组、对象)交互需要特定策略:
方法一:通过内存复制
- JS 将字符串/数组写入 wasm 的线性内存
- wasm 读取并操作这些内存地址
const encoder = new TextEncoder();
const encoded = encoder.encode("hello wasm");const memory = instance.exports.memory;
const buffer = new Uint8Array(memory.buffer, ptr, encoded.length);
buffer.set(encoded);
方法二:对象间接引用
通过建立一个“堆”对象系统,JS 把对象存在堆中,Rust 使用整数索引引用这些对象,然后通过导入函数调用 JS 方法来操作这些对象。
这是 wasm-bindgen
等工具背后的核心机制。
4. wasm-bindgen 简化互操作
wasm-bindgen
是官方支持的互操作框架,提供了自动绑定 Rust/JS 的方法和类型,使得写代码更自然、更安全:
use wasm_bindgen::prelude::*;#[wasm_bindgen]
extern "C" {fn alert(s: &str);
}#[wasm_bindgen]
pub fn greet(name: &str) {alert(&format!("Hello, {}!", name));
}
这个代码编译后可以直接被 JavaScript 调用:
import init, { greet } from './pkg/your_wasm_module.js';await init();
greet("ChatGPT");
5. 自定义 Section:传递静态数据
Rust 支持通过自定义 Section 将任意静态数据打包进 .wasm
文件中,例如用于版本信息、签名、配置等:
#[link_section = "hello"]
pub static SECTION: [u8; 24] = *b"This is a custom section";
在 JS 中可通过 WebAssembly.Module.customSections
读取:
WebAssembly.compileStreaming(fetch("sections.wasm")).then(mod => {const sections = WebAssembly.Module.customSections(mod, "hello");const text = new TextDecoder().decode(sections[0]);console.log(text); // 输出:This is a custom section});
总结
方向 | 技术 | 说明 |
---|---|---|
Rust → JS | #[link(wasm_import_module)] extern | 导入 JS 函数 |
Rust → JS | #[no_mangle] pub extern fn | 导出函数给 JS 使用 |
JS → Rust | WebAssembly.instantiate() | 调用 wasm 导出函数 |
高级交互 | 内存映射、对象堆、wasm-bindgen | 实现复杂类型传递 |
静态数据 | Custom Section + customSections() | 从 wasm 中读取自定义静态数据 |