Why Browsers Suddenly Started Speaking a New Language?
Imagine you are a chef. JavaScript is your universal knife: you can cut bread, clean fish, and even open cans (with the risk of cutting yourself). And WebAssembly is a professional Japanese knife for slicing sashimi. It does one thing — cuts perfectly thin and fast, but requires a special approach. You won't use it to peel potatoes, but when you need to slice 100 portions of tuna in a minute — you can't do without it.
In the world of web development, one king ruled for a long time — JavaScript. But in 2017, a new player entered the scene: WebAssembly (Wasm). It is not a replacement for JS, but its powerful partner. Today we'll figure out what this beast is, why it's needed, and how to tame it with JavaScript.
What is WebAssembly in Simple Terms?
WebAssembly is a low-level binary instruction format that runs in the browser at near-native speed. If JavaScript is text that the browser reads and interprets on the fly, then Wasm is ready-compiled bytecode, similar to machine code.
You write code in C, C++, or Rust, compile it into a .wasm file, and then load it into the browser like a regular script. The browser executes it directly, bypassing the long parsing and JIT-compilation stage that JavaScript goes through.
Key features of WebAssembly:
- Speed — execution close to native (2–10 times faster than JS in computational tasks).
- Security — runs in an isolated sandbox, like JS.
- Compactness — .wasm files take up little space and load quickly.
- Integration — easily called from JavaScript and vice versa.
Why is This Needed if JavaScript Exists?
JavaScript is great for 95% of tasks: working with the DOM, animations, event handling, server requests. But there are tasks where JS falls short:
- Heavy computations — video processing, 3D rendering, physics simulations.
- Games — AAA projects on Unity or Unreal Engine.
- Scientific calculations — molecular dynamics simulation, cryptography.
- Working with media — image compression/decompression, audio and video codecs.
In these scenarios, WebAssembly provides a performance boost of tens of times. At the same time, you don't lose access to browser APIs (through a JS wrapper).
How Does It Work? Simple Architecture
Imagine a bridge between two worlds. On one side is your .wasm module (fast, but "dumb" — it doesn't know about the DOM or events). On the other side is JavaScript (slower, but "smart" — it can do everything). They communicate through a special "memory" — Wasm linear memory.
JS allocates an array of bytes (ArrayBuffer), passes it to the Wasm module, which fills it with data, and JS retrieves the result. This is like passing a heavy box through a window — you don't hand over each item separately, but pass the entire box at once.
Writing a Real Example: Speeding Up Factorial
Let's compare performance on a classic task — calculating factorial. First, we'll implement it in pure JavaScript, and then in C, compiled to Wasm.
1. JavaScript version (regular)
// factorial.jsfunction factorialJS(n) { let result = 1; for (let i = 2; i <= n; i++) { result *= i; } return result;}
// Testconsole.time('JS');for (let i = 0; i < 100000; i++) { factorialJS(20);}console.timeEnd('JS'); // ~15-25 ms in Chrome2. C code that we will compile to Wasm
First, write in C:
// factorial.cint factorial(int n) { int result = 1; for (int i = 2; i <= n; i++) { result *= i; } return result;}<