WebAssembly (Wasm)
TL;DR
Explanation
WebAssembly is a low-level bytecode format designed as a compilation target for languages like C, C++, Rust, and Go. Browsers execute Wasm at near-native speed via a sandboxed virtual machine alongside the JS engine. Wasm modules can be instantiated from JavaScript, share memory via a linear memory buffer, and call JS functions as imports. On the server side, WASI (WebAssembly System Interface) provides a portable, sandboxed runtime model used in edge computing (Cloudflare Workers, Fastly Compute). PHP can run compiled to Wasm via the php-wasm project, enabling PHP execution in the browser. Key use cases: CPU-intensive computations (image processing, codecs, compression), porting existing native libraries to the web without rewriting, and untrusted code sandboxing. Wasm does not replace JavaScript for DOM manipulation — it cannot access the DOM directly and must call JS for any browser API interaction.
Watch Out
Common Misconception
Why It Matters
Common Mistakes
- Reaching for Wasm to speed up I/O-bound JS code — Wasm only helps CPU-bound work; network and DOM operations are no faster.
- Ignoring the JS/Wasm bridge cost — frequent small calls between JS and Wasm via imports/exports add significant overhead; batch operations.
- Shipping unoptimised Wasm binaries — without wasm-opt or LTO, compiled output can be significantly larger and slower than necessary.
Avoid When
- Do not use Wasm for DOM manipulation, network requests, or anything that must call browser APIs — JS is faster for those due to bridge overhead.
- Avoid Wasm when the compiled binary size outweighs the performance gain for your use case — a 2 MB Wasm module adds to initial load time.
- Do not reach for Wasm before profiling — most web performance bottlenecks are I/O or rendering, not CPU computation.
When To Use
- Use Wasm for CPU-bound browser tasks: image/video processing, audio codecs, compression, cryptography, simulation.
- Use it to port existing C/C++/Rust libraries to the browser without rewriting them in JavaScript.
- Consider Wasm for sandboxed execution of untrusted code — the Wasm VM provides strong isolation by default.
Code Examples
// Calling Wasm per-pixel — bridge overhead dominates:
const wasmProcess = instance.exports.processPixel;
for (let i = 0; i < pixels.length; i += 4) {
pixels[i] = wasmProcess(pixels[i]); // JS→Wasm per pixel
}
// Pass entire buffer to Wasm — one bridge call:
const ptr = instance.exports.alloc(pixels.length);
new Uint8Array(instance.exports.memory.buffer, ptr, pixels.length).set(pixels);
instance.exports.processImage(ptr, pixels.length); // single call
const result = new Uint8Array(instance.exports.memory.buffer, ptr, pixels.length);