For CPU-heavy tasks like image/matrix/crypto in browser, JS hits performance limits. WASM compiles Rust to near-native bytecode running in every modern browser.
Toolchain and Basic Bindings
Install wasm-pack and use #[wasm_bindgen] to export Rust functions callable from JS. Complex structs cross via serde + serde_wasm_bindgen serialization.
use wasm_bindgen::prelude::*;
use serde::{Serialize, Deserialize};
use web_sys::console;
#[derive(Serialize, Deserialize)]
pub struct MatrixResult { rows: usize, cols: usize, data: Vec<f64>, compute_ms: f64 }
#[wasm_bindgen(start)]
pub fn init() {
console_error_panic_hook::set_once();
console::log_1(&"[WASM] Matrix module loaded".into());
}
#[wasm_bindgen]
pub fn matrix_multiply(a_ptr: *mut f64, a_rows: usize, a_cols: usize, b_ptr: *mut f64, b_cols: usize) -> JsValue {
use std::time::Instant;
let t0 = Instant::now();
let a = unsafe { std::slice::from_raw_parts(a_ptr, a_rows * a_cols) };
let b = unsafe { std::slice::from_raw_parts(b_ptr, a_cols * b_cols) };
let mut c = vec![0.0f64; a_rows * b_cols];
for i in 0..a_rows {
for k in 0..a_cols {
let aik = a[i * a_cols + k];
let rb = &b[k * b_cols..(k + 1) * b_cols];
let rc = &mut c[i * b_cols..(i + 1) * b_cols];
for j in 0..b_cols { rc[j] += aik * rb[j]; }
}
}
let r = MatrixResult { rows: a_rows, cols: b_cols, data: c, compute_ms: t0.elapsed().as_secs_f64() * 1000.0 };
serde_wasm_bindgen::to_value(&r).unwrap()
}
#[wasm_bindgen]
pub fn fibonacci_iter(n: u32) -> u64 {
if n <= 1 { return n as u64; }
let (mut prev, mut curr) = (0u64, 1u64);
for _ in 2..=n { let next = prev.saturating_add(curr); prev = curr; curr = next; }
curr
}
#[wasm_bindgen(js_name = "allocateFloat64Array")]
pub fn allocate_f64(len: usize) -> *mut f64 {
let mut v = Vec::with_capacity(len);
let p = v.as_mut_ptr();
std::mem::forget(v);
p
}
JS Invocation and Memory Sharing
WASM memory is a shared ArrayBuffer; reading/writing through TypedArray views is 10-100x faster than serialization. Allocate from JS into WASM memory then pass pointers/sizes for large data.
| Metric | Plain JS | WASM (Rust) | Speedup | Best For |
|---|---|---|---|---|
| Matmul 1024x1024 | ~1800ms | ~85ms | ~21x | 3D/Games/AI |
| Fibonacci(n=40) | ~980ms | ~8ms | ~120x | Math workloads |
| SHA-256 1MB | ~42ms | ~6ms | ~7x | Crypto/Checksums |
Best Practices
Target compute-heavy loops, not DOM work. Prefer TypedArray memory sharing for large data over serialized parameters. Use wasm-opt on release builds to shrink binary size.