开头
先说结论:能,但别指望它解决所有前端性能问题。
我最早接触 WebAssembly 是在 2017 年,当时各大浏览器的支持度还磕磕绊绊。看着那些 demo —— 浏览器里跑 Unity 游戏、实时视频处理,心里就痒痒:这玩意儿是不是能让 JavaScript 那点可怜的计算能力原地起飞?
但真正动手写起来,才发现事情没那么简单。今年趁项目间隙,我专门搭了个小实验:用 Rust 写了个 WebAssembly 模块,跑一个比较重的计算任务,跟纯 JavaScript 硬刚了一把。下面直接看代码和结果。
实验:计算斐波那契数列第 40 项
任务很俗,但对比明显。
JavaScript 版
function fibJS(n) {
if (n <= 1) return n;
return fibJS(n-1) + fibJS(n-2);
}
console.time('JS');
console.log(fibJS(40));
console.timeEnd('JS');WebAssembly 版(Rust 编译)
首先,Rust 源码 src/lib.rs:
#[no_mangle]
pub extern "C" fn fib_wasm(n: u32) -> u32 {
if n <= 1 {
return n;
}
fib_wasm(n - 1) + fib_wasm(n - 2)
}编译成 wasm 后用 wasm-bindgen 生成胶水代码,然后在 JS 里调用:
import init, { fib_wasm } from './pkg/wasm_perf.js';
async function run() {
await init();
console.time('Wasm');
console.log(fib_wasm(40));
console.timeEnd('Wasm');
}
run();结果(Chrome 118, MacBook M1 Pro)
| 实现 | 耗时 (ms) |
|---|---|
| JS | 1032 |
| Wasm | 342 |
快了大约 3 倍。而且随着 n 增大,差距还会拉大。

为什么 Wasm 更快?
简单说几个点:
- 类型确定:wasm 的变量类型在编译时就是固定的,没有 JS 的动态类型和 JIT 优化的预热/去优化开销。
- 内存管理直接:wasm 操作线性内存,没有 GC 干扰,循环里分配临时对象?不存在的。
- 体积小:二进制格式,解析快。
但注意:这里我用了最朴素的递归,没做优化。实际项目中这种纯 CPU 密集任务其实不太常见,更常见的是对大量数据的处理,比如图像像素操作、物理引擎碰撞计算。那种场景下,Wasm 的缓存友好性也强很多。
一个反直觉的例子:字符串操作
我接着试了试字符串拼接和正则匹配。结果 Wasm 反而更慢,因为涉及 JS 和 Wasm 之间的边界数据传递。每次传字符串都要编解码,得不偿失。
// 字符串拼接 demo (Rust)
#[wasm_bindgen]
pub fn concat_strings(a: &str, b: &str) -> String {
format!("{}{}", a, b)
}调用时,JS 的字符串先被复制到 Wasm 内存,处理完再复制回来。对于几 MB 的大文本,开销就很大了。所以别想着用 Wasm 做 DOM 操作或大量字符串处理,那还是 JS 的天下。
到底什么场景适合上 Wasm?
根据我的实测和思考,总结了三个靠谱方向:
- 计算密集型算法:数值计算、加密、音视频编解码、物理引擎。比如市场上那些“浏览器里跑 FFmpeg”的项目,基本都是 Wasm 驱动的。
- 移植已有 C/C++/Rust 库:不想重写,就直接编译。比如 SQLite、libjpeg、opencv。但不能无脑用,要看接口复杂度。
- 游戏和图形渲染:Unity 小游戏,或者像 Google Earth 那种需要大量 3D 渲染的,Wasm 比 asm.js 更高效。
至于“替代 JavaScript”这种话,听听就好。Wasm 没有 GC,不能直接操作 DOM,生态也远不如 JS 成熟。它更像是个“性能协处理器”。
开发的真实体验
老实说,开发体验挺糟心的。调试麻烦,堆栈信息一团乱,没有 source map 时跟裸写汇编差不多。Rust 的 wasm 工具链还算好的,C++ 用 Emscripten 那套更是让人头大。
另外,包体积也要注意。一个最小的 Rust wasm 模块,光“Hello World”就有 2KB 左右,加上胶水代码和依赖,很容易膨胀到几十 KB。对于移动端,首屏加载还是得掂量掂量。
最后说点个人看法
我虽然踩了坑,但觉得 Wasm 确实是有用的工具。它让前端第一次拥有接近原生的计算能力。但前提是你清楚它的适用边界。别听人一吹“Wasm 性能起飞”就脑袋发热全上,先问自己:我要解决的问题是“计算密集型”吗?如果是,那就大胆用;如果不是,JS 的异步和事件驱动才是主流。
我后面还会再试 WebAssembly 的 SIMD 和多线程(Threads proposal),那时候估计又有新故事可以聊。
觉得内容不错?我要