WebAssembly导出的函数怎么在JS里调用不生效?

欧阳可慧 阅读 9

我用Rust编译了一个.wasm文件,导出了一个add函数,但在JS里调用时总是undefined,不知道是哪步出错了。已经确认wasm加载成功了,但instance.exports里看不到我的函数。

这是我在HTML里加载和调用的代码:

<script type="module">
  const wasm = await WebAssembly.instantiateStreaming(fetch('pkg/my_wasm_bg.wasm'));
  console.log(wasm.instance.exports); // 这里没看到add函数
  // const result = wasm.instance.exports.add(1, 2); // 报错:add is not a function
</script>
我来解答 赞 3 收藏
二维码
手机扫码查看
1 条解答
开发者星宇
这个问题很典型,你应该是用了wasm-bindgen来编译Rust代码对吧?wasm-bindgen生成的wasm文件不能直接手动实例化,它需要配合生成的JS胶水代码一起使用。

问题原因:wasm-bindgen在编译时会生成两部分东西,一个是.wasm二进制文件,另一个是.js胶水代码。你只加载了.wasm,但那些导出函数实际上是通过JS胶水代码包装之后才能正常调用的。

正确的做法是这样的:

首先,确保你的Rust代码里函数标记了 #[wasm_bindgen],比如:

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}


然后编译的时候用 wasm-pack build --target web

在HTML/JS里正确的调用方式应该是:

// 导入wasm-bindgen生成的JS初始化函数
import init, { add } from './pkg/my_wasm.js';

async function run() {
// 先调用init()初始化wasm模块
await init();

// 然后直接调用导出的函数
const result = add(1, 2);
console.log(result); // 输出3
}

run();


你之前那么写的问题是,wasm-bindgen导出的函数实际上是通过JS胶水代码里的WebAssembly.Instance在内部处理过的,不是直接放在instance.exports里的。你需要先跑一遍init(),它会帮你正确实例化wasm并把导出函数暴露出来。

如果你不想用wasm-bindgen,想直接裸写wasm导出,那也行,但就得用wasm-bindgen-cli或者直接用wat手写WebAssembly文本格式了,那样导出函数会直接出现在instance.exports里。不过既然你已经在用Rust了,用wasm-bindgen还是最省心的办法。
点赞
2026-03-11 14:01