WebAssembly
Zusammenfassung
WebAssembly — Wasm — is a binary instruction format for a stack-based virtual machine, designed to run in web browsers at near-native speed. First shipped in major browsers in 2017, it allows code written in C, C++, Rust, Go, and dozens of other languages to run on the web without being recompiled to JavaScript. Wasm emerged from a decade of failed attempts to give the web a second language, but succeeded where its predecessors failed by being a compiler target rather than a programming language — nobody writes Wasm by hand. Since 2019, Wasm has expanded beyond the browser through the WebAssembly System Interface (WASI), becoming a universal portable binary format for cloud functions, edge computing, and plugin systems. It is the closest thing the computing industry has produced to the Java VM’s “write once, run anywhere” promise — this time, it appears to be working.
The Problem: JavaScript’s Monopoly
For most of the web’s history, JavaScript was the only language that could run inside a browser. This was not a design decision — it was an accident of history. Brendan Eich wrote JavaScript in ten days in 1995 for Netscape, and it became the dominant browser language simply because it was first and because every browser included it. No subsequent attempt to add a second language to the browser succeeded.
Java applets were the first serious alternative. Sun designed them explicitly for browser execution: a JVM embedded in the browser would run Java bytecode with the same performance Java applications achieved on the desktop. In the late 1990s, Java applets were widespread. But applets required a browser plugin, loaded slowly, had security vulnerabilities, and felt alien inside a web page. By 2010, Apple had excluded Java from iOS; by 2017, all major browsers had removed Java plugin support.
Flash (Macromedia, then Adobe) achieved broader adoption than Java for interactive web content. Flash’s vector graphics, animation tools, and video capabilities made it the platform for YouTube, online games, and rich web applications through the 2000s. But Flash was a proprietary plugin, had chronic security vulnerabilities, performed poorly on mobile hardware, and drained laptop batteries. Steve Jobs’s 2010 open letter “Thoughts on Flash” — announcing that iOS would never support Flash — accelerated its decline. Adobe discontinued Flash Player in 2020.
Native Client (NaCl) was Google’s 2011 attempt to run native x86 code in Chrome through a security sandbox. It worked — running native code at near-native speeds — but was so complex to sandbox correctly that only Google supported it. Porting applications required NaCl-specific toolchains and produced binaries that only ran in Chrome.
asm.js (2013, Mozilla) was a different approach: compile C/C++ code to a highly optimized subset of JavaScript that Firefox’s JIT compiler could run at near-native speed. The project, led by Alon Zakai and his Emscripten compiler, demonstrated that C code could run in a browser at 50–75% of native speed. But asm.js was still JavaScript — it inherited JavaScript’s parsing overhead, variable-length representation, and all the semantic complexity that made optimizing JavaScript difficult.
The Design of WebAssembly
The breakthrough came from recognizing that asm.js’s approach was correct — compile high-level languages to a portable intermediate representation — but that the intermediate representation should not be JavaScript. In 2015, Mozilla, Google, Microsoft, and Apple agreed to jointly design a new binary format specifically for this purpose.
The design goals were explicit:
- Fast to execute: Wasm bytecode could be decoded and compiled to native code faster than JavaScript could be parsed and JIT-compiled.
- Compact: Binary encoding is smaller than text; Wasm files compress well.
- Safe: All memory accesses are bounds-checked. Wasm code cannot access memory outside its allocated sandbox. The execution model provides the same security guarantees as JavaScript.
- Language-agnostic: Wasm is a compiler target, not a source language. Any language with a Wasm backend can target it.
- Interoperable with JavaScript: Wasm modules can call JavaScript functions and be called by JavaScript, enabling gradual adoption in existing web applications.
The WebAssembly specification was published in 2019 as a W3C standard. All major browsers shipped initial support in 2017, making Wasm’s rollout faster than any previous web standard.
LLVM (the modular compiler infrastructure) gained a Wasm backend early in the process. This meant that any language with an LLVM frontend — C, C++, Rust, Swift, Kotlin/Native — could target Wasm immediately. Emscripten (originally the asm.js compiler) became the primary toolchain for C/C++ to Wasm. wasm-pack and wasm-bindgen provided the Rust ecosystem’s bridge. AssemblyScript provided a TypeScript-like syntax that compiled directly to Wasm.
Performance and Capabilities
WebAssembly’s performance advantage over JavaScript is real but context-dependent.
For CPU-intensive computation — image processing, video encoding, cryptography, game physics, audio synthesis, scientific simulation — Wasm consistently outperforms JavaScript by factors of 2–10x. The gap reflects fundamental differences: Wasm’s type system allows ahead-of-time compilation to native code; JavaScript’s dynamic types require runtime type checking and speculation. Wasm startup time is lower because the binary format requires less parsing.
For memory-bound or I/O-bound operations — network requests, DOM manipulation, user interface rendering — JavaScript and Wasm perform similarly, since both ultimately wait on the same underlying operations.
The performance ceiling matters for specific applications. Figma, the browser-based design tool, uses Wasm for its rendering engine; the application’s smooth performance in a browser was only possible because Wasm eliminated JavaScript’s performance bottleneck. Google Earth on the web relies on Wasm for its 3D rendering. AutoCAD’s web client compiles 35 years of C++ code to Wasm. Game engines including Unity and Unreal Engine provide Wasm export targets.
Beyond the Browser: WASI
In 2019, Mozilla’s Lin Clark proposed the WebAssembly System Interface (WASI) — a standard API for Wasm modules running outside the browser, providing access to files, networking, clocks, and random numbers in a capability-based security model.
WASI’s motivation was straightforward: if Wasm provided a secure, portable, fast execution environment, why limit it to browsers? A Wasm module compiled with WASI support could run on any server, serverless function platform, or edge computing node that implemented the WASI runtime — without recompilation.
Solomon Hykes, Docker’s creator, wrote in 2019: “If WASM+WASI existed in 2008, we wouldn’t have needed to create Docker. That’s how important it is. Webassembly on the server is the future of computing.”
The comparison is apt. Docker containers solve the “runs on my machine” problem by packaging an application with its dependencies in a container image. Wasm+WASI solves the same problem differently: instead of packaging the environment, the application compiles to a bytecode that every compliant runtime executes identically. The Wasm module is smaller than a Docker image, starts faster (milliseconds vs. seconds), and is sandboxed by design.
Cloudflare Workers, Fastly Compute@Edge, and Fastly Lucet runtime used Wasm as the execution format for serverless edge functions, allowing code to run in hundreds of points-of-presence with sub-millisecond cold starts. Fermyon Spin and wasmtime (the Bytecode Alliance’s reference runtime) made Wasm a general-purpose server-side runtime.
The Component Model and the Future
Wasm’s initial design was deliberately minimal — a binary format for computation, with JavaScript as the only external interface. This minimalism made adoption fast but created friction: passing complex data types between Wasm and JavaScript required awkward memory-copying conventions.
The Component Model (under active development as of 2024) addresses this by defining a standard interface type system that allows Wasm modules written in different languages to call each other directly, passing complex values without manual serialization. A Rust Wasm module can call a Python Wasm module using natural function calling conventions; neither needs to know the other’s implementation language.
WebAssembly System Interface (WASI) 0.2 shipped in 2024, the first stable version of WASI based on the Component Model. This release marked Wasm’s maturation from browser optimization to general-purpose portable runtime.
The trajectory suggests Wasm is converging on a role similar to what the JVM attempted in 1996 — a universal execution environment that any language can target and any platform can implement — but with the architectural lessons of two decades of JVM experience incorporated: security by default, language-agnostic design, and a governance process that prevents any single vendor from controlling the standard.
📚 Sources
- WebAssembly W3C Standard — the official specification published 2019
- WebAssembly: A New Hope (2017) — Lin Clark’s accessible illustrated introduction to Wasm’s design
- Asm.js specification — Mozilla’s 2013 precursor; shows the design evolution toward Wasm
- WASI announcement — Lin Clark’s 2019 announcement and design rationale
- WebAssembly Component Model — Bytecode Alliance specification for cross-language Wasm module composition
- Figma’s use of WebAssembly — how Wasm cut Figma’s load time by 3x