WebAssembly在HTML5中通过instantiateStreaming高效加载,JS与Wasm通过共享内存和导出/导入函数交互,仅支持基本数值类型传参,字符串和数组需手动编码读写,Wasm可调用JS导入函数。

WebAssembly(Wasm)在HTML5中通过JavaScript API加载和运行,核心是 WebAssembly.instantiate() 或更现代的 WebAssembly.instantiateStreaming()。JS与Wasm的数据交互主要依赖内存共享(WebAssembly.Memory)和导出/导入函数,而非直接传递复杂对象。
加载Wasm模块:推荐使用 instantiateStreaming
若Wasm文件以 .wasm 二进制形式部署(MIME类型 application/wasm),instantiateStreaming 最高效,支持流式解析,避免完整下载后再编译:
async function loadAndRun() {
const response = await fetch('module.wasm');
const { instance } = await WebAssembly.instantiateStreaming(response);
return instance;
}
注意:确保服务器正确返回 Content-Type: application/wasm,否则会回退到低效的 instantiate + arrayBuffer 方式。
JS调用Wasm导出函数:直接访问 exports 对象
Wasm模块编译后,其导出的函数、变量、内存等都挂载在 instance.exports 上。例如,一个导出加法函数 add(a, b) 的模块:
立即学习“前端免费学习笔记(深入)”;
const { instance } = await WebAssembly.instantiateStreaming(fetch('math.wasm'));
const result = instance.exports.add(3, 5); // 返回 8
- 参数和返回值仅支持基本数值类型(
i32,i64,f32,f64) - 字符串、数组等需手动在共享内存中读写(见下一条)
- 导出函数本质是同步调用,无Promise包装
在JS与Wasm间传递字符串和数组:操作共享线性内存
Wasm默认只有一块可读写的线性内存(WebAssembly.Memory),JS和Wasm通过同一段 ArrayBuffer 交换数据:
// 假设 Wasm 模块导出了 memory 和一个写入字符串的函数 writeString
const { instance } = await WebAssembly.instantiateStreaming(fetch('string.wasm'));
const memory = instance.exports.memory;
const heap = new Uint8Array(memory.buffer);
// JS向Wasm内存写入字符串(UTF-8编码)
function writeToWasm(str) {
const encoder = new TextEncoder();
const bytes = encoder.encode(str);
const ptr = instance.exports.alloc(bytes.length); // Wasm中分配足够空间
heap.set(bytes, ptr);
return ptr;
}
// JS从Wasm内存读取字符串
function readFromWasm(ptr, len) {
const bytes = heap.slice(ptr, ptr + len);
const decoder = new TextDecoder();
return decoder.decode(bytes);
}
- Wasm需提供内存分配函数(如
alloc(size))或约定内存布局(如固定偏移) - JS侧用
TextEncoder/TextDecoder处理UTF-8字符串,避免字节错位 - 数组同理:JS将
Float32Array写入内存,Wasm按对应指针+长度读取
Wasm调用JS函数:通过 import 机制传入回调
可在实例化时向Wasm导入JS函数,供Wasm内部调用(常用于日志、I/O、DOM操作等无法在Wasm中直接完成的任务):
const importObj = {
env: {
console_log: (ptr, len) => {
const bytes = new Uint8Array(memory.buffer, ptr, len);
const str = new TextDecoder().decode(bytes);
console.log('[Wasm]', str);
}
}
};
const { instance } = await WebAssembly.instantiateStreaming(
fetch('logger.wasm'),
importObj
);
- 导入对象结构必须与Wasm的
import声明严格匹配(模块名、函数名、签名) - 导入函数内可安全调用任意JS API,但要注意跨语言调用开销
- 若Wasm未声明该导入,实例化会失败并抛出
LinkError



















