WebAssembly 与 JavaScript 的互操作是其核心功能之一,通过导入导出机制实现:
1. 导入 JavaScript 函数到 WebAssembly WebAssembly 可以导入 JavaScript 函数并在内部调用:
javascript// JavaScript 代码 const importObject = { env: { log: (value) => console.log(value), add: (a, b) => a + b, currentTime: () => Date.now() } }; // 加载 WebAssembly 模块 WebAssembly.instantiateStreaming(fetch('module.wasm'), importObject) .then(results => { // WebAssembly 模块可以调用导入的函数 });
2. 导出 WebAssembly 函数给 JavaScript WebAssembly 模块可以导出函数供 JavaScript 调用:
javascript// 加载 WebAssembly 模块后 const wasmModule = results.instance; // 调用导出的函数 const result = wasmModule.exports.add(10, 20); console.log(result); // 30
3. 内存共享 JavaScript 和 WebAssembly 可以共享内存:
javascript// 创建共享内存 const memory = new WebAssembly.Memory({ initial: 10, maximum: 100 }); // 将内存传递给 WebAssembly const importObject = { env: { memory: memory } }; // JavaScript 可以访问内存 const buffer = new Uint8Array(memory.buffer); buffer[0] = 42; // WebAssembly 也可以访问同一块内存
4. 数据类型转换 JavaScript 和 WebAssembly 之间的数据类型转换:
| JavaScript | WebAssembly |
|---|---|
| Number | f32, f64, i32, i64 |
| BigInt | i64 |
| TypedArray | 内存视图 |
| Array | 需要手动转换 |
javascript// JavaScript 调用 WebAssembly 函数 const result = wasmModule.exports.processData( 42, // i32 3.14, // f64 BigInt(123) // i64 ); // WebAssembly 返回数据 const wasmResult = wasmModule.exports.getData(); const view = new Uint32Array(memory.buffer, offset, length);
5. 复杂数据结构 对于复杂数据结构,需要手动序列化和反序列化:
javascript// 传递对象 function sendObjectToWasm(obj) { const jsonString = JSON.stringify(obj); const encoder = new TextEncoder(); const encoded = encoder.encode(jsonString); // 写入 WebAssembly 内存 const buffer = new Uint8Array(memory.buffer); buffer.set(encoded, 0); // 调用 WebAssembly 函数 wasmModule.exports.processObject(0, encoded.length); } // 从 WebAssembly 接收对象 function receiveObjectFromWasm(offset, length) { const buffer = new Uint8Array(memory.buffer); const slice = buffer.slice(offset, offset + length); const decoder = new TextDecoder(); const jsonString = decoder.decode(slice); return JSON.parse(jsonString); }
6. 异步操作 WebAssembly 本身不支持异步,但可以通过 JavaScript 实现:
javascript// WebAssembly 调用异步 JavaScript 函数 const importObject = { env: { fetchData: async (url) => { const response = await fetch(url); return response; } } };
7. 错误处理 处理 WebAssembly 和 JavaScript 之间的错误:
javascripttry { const result = wasmModule.exports.mightFail(); } catch (error) { console.error('WebAssembly error:', error); }
8. 性能优化
- 减少跨边界调用的次数
- 使用共享内存避免数据复制
- 批量处理数据
- 使用 TypedArray 高效传输二进制数据
9. 最佳实践
- 明确定义导入导出接口
- 使用 TypeScript 类型定义提高类型安全
- 合理设计数据交换格式
- 考虑性能和开发体验的平衡
- 使用工具简化互操作(如 wasm-bindgen)