
WebAssembly 实战:在浏览器中运行高性能代码
WebAssembly (Wasm) 是一种二进制指令格式,可在现代浏览器中以接近原生速度运行。它允许你将 C、C++、Rust、Go 等语言编译为可移植的二进制文件,与 JavaScript 并行运行。
为什么选择 WebAssembly?
- 性能:以接近原生速度运行,对于计算密集型任务远快于 JS
- 可移植性:同一二进制文件可在任何浏览器或 Node.js 中运行
- 语言灵活性:在 Rust、C++ 擅长的领域使用它们
- 安全性:在沙盒环境中运行

将 Rust 编译为 WebAssembly
# 安装 wasm-pack
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
# 创建一个新的 Rust + Wasm 项目
wasm-pack new hello-wasm
cd hello-wasm
// src/lib.rs
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u32 {
match n {
0 => 0,
1 => 1,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
#[wasm_bindgen]
pub fn greet(name: &str) -> String {
format!("Hello, {}! From WebAssembly.", name)
}
# 为 Web 构建
wasm-pack build --target web
在 JavaScript 中使用 Wasm
import init, { fibonacci, greet } from './pkg/hello_wasm.js';
async function run() {
await init();
console.log(greet("World")); // "Hello, World! From WebAssembly."
const start = performance.now();
const result = fibonacci(40);
const end = performance.now();
console.log(`fibonacci(40) = ${result}, took ${end - start}ms`);
}
run();

内存管理
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct ImageProcessor {
width: u32,
height: u32,
data: Vec<u8>,
}
#[wasm_bindgen]
impl ImageProcessor {
#[wasm_bindgen(constructor)]
pub fn new(width: u32, height: u32) -> ImageProcessor {
ImageProcessor {
width,
height,
data: vec![0; (width * height * 4) as usize],
}
}
pub fn grayscale(&mut self) {
let pixels = self.data.chunks_mut(4);
for pixel in pixels {
let gray = (0.299 * pixel[0] as f32
+ 0.587 * pixel[1] as f32
+ 0.114 * pixel[2] as f32) as u8;
pixel[0] = gray;
pixel[1] = gray;
pixel[2] = gray;
}
}
pub fn data_ptr(&self) -> *const u8 {
self.data.as_ptr()
}
}
性能最佳实践
// 1. 最小化 JS-Wasm 边界跨越
// 错误:在循环中跨越边界
for (let i = 0; i < 1000000; i++) {
wasmModule.process_single_item(i);
}
// 正确:将批量数据传递给 Wasm
wasmModule.process_all_items(dataArray, 1000000);
// 2. 大型 Wasm 文件的流式编译
const { instance } = await WebAssembly.instantiateStreaming(
fetch('/module.wasm'),
importObject
);

WASI:浏览器之外的 Wasm
// WASI 允许 Wasm 作为服务端运行时运行
fn main() {
println!("Hello from WASI!");
let content = std::fs::read_to_string("input.txt").unwrap();
println!("File content: {}", content);
}
# 使用 wasmtime 运行
cargo build --target wasm32-wasi
wasmtime target/wasm32-wasi/debug/my-app.wasm
实际用例
- 视频/图像处理:ffmpeg.wasm 用于客户端视频转换
- 密码学:快速加密操作(bcrypt、AES)
- 游戏引擎:Quake、Doom 在浏览器中运行
- 科学计算:浏览器中的 Python(Pyodide)
- SQLite:sql.js 用于客户端数据库
总结
WebAssembly 使得在浏览器中运行高性能代码成为可能。关键要点:
- 对 CPU 密集型工作使用 Rust 或 C++
- 最小化 JS/Wasm 边界跨越
- 使用类型化数组实现高效内存共享
- 考虑使用 WASI 实现可移植的服务端 Wasm