WebAssembly 入门教程 / 01 - WebAssembly 概述
01 - WebAssembly 概述
WebAssembly 不是要取代 JavaScript,而是要成为它的"高性能搭档"。
1.1 什么是 WebAssembly?
WebAssembly(简称 Wasm)是一种基于堆栈的二进制指令格式(binary instruction format),被设计为高级编程语言(如 C、C++、Rust)的可移植编译目标。它可以在 Web 浏览器和非浏览器环境中以接近原生的速度运行。
关键特性
| 特性 | 说明 |
|---|---|
| 快速 | 二进制格式接近原生机器码执行速度 |
| 安全 | 在内存安全的沙箱(sandbox)中执行 |
| 开放 | W3C 标准,开放且可调试 |
| 可移植 | 不依赖特定平台或操作系统 |
| 紧凑 | 二进制格式体积小,加载快 |
| 多语言 | 支持 C/C++、Rust、Go、C#、AssemblyScript 等 |
核心设计目标
WebAssembly 的设计目标由 W3C 工作组明确制定:
- 定义可移植的、体积紧凑的二进制格式,以快速加载和执行
- 可以在各种平台上编译,包括移动设备和 IoT
- 执行速度接近原生,充分利用硬件能力
- 支持非 Web 嵌入(通过 WASI 等接口)
1.2 WebAssembly vs JavaScript
理解 Wasm 最好的方式是与 JavaScript 对比:
| 对比维度 | JavaScript | WebAssembly |
|---|---|---|
| 格式 | 文本源码(ESM/CJS) | 二进制字节码 |
| 解析 | 需要解析、AST 编译 | 直接解码为模块 |
| 类型 | 动态类型 | 静态类型(i32/i64/f32/f64) |
| 执行模型 | 解释 + JIT | AOT / JIT |
| 内存管理 | 垃圾回收(GC) | 线性内存,手动管理 |
| 适用场景 | DOM 操作、业务逻辑 | 计算密集型、移植原生代码 |
| 学习曲线 | 相对较低 | 较高(需了解底层概念) |
💡 关键理解:Wasm 并不"比 JS 快"——它适合不同的场景。在 DOM 操作等场景中,JS 仍然是最佳选择;而在图像处理、加密、编解码等计算密集场景中,Wasm 优势明显。
性能对比示例
// JavaScript — 计算斐波那契数列(递归)
function fib(n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
console.time('js');
console.log(fib(40));
console.timeEnd('js');
对应的 C 编译为 Wasm 后,执行同一算法的典型性能对比:
| n | JS 时间 (ms) | Wasm 时间 (ms) | 倍数 |
|---|---|---|---|
| 30 | ~15 | ~3 | ~5x |
| 35 | ~180 | ~35 | ~5x |
| 40 | ~2200 | ~400 | ~5.5x |
| 45 | ~26000 | ~4500 | ~5.8x |
⚠️ 注意:以上数据为典型参考值,实际性能因浏览器版本、CPU 架构等因素而异。
1.3 与其他技术的关系
WebAssembly 与 asm.js
asm.js 是 Wasm 的"前身"——它是一种 JavaScript 的严格子集,浏览器可以对其做 AOT 优化:
asm.js(文本)→ 浏览器 AOT → 接近原生速度
Wasm(二进制)→ 浏览器 AOT → 接近原生速度(更快解析)
Wasm 之所以取代 asm.js,是因为:
- 二进制格式体积更小(通常只有 asm.js 的 30%-50%)
- 解码速度比解析 JS 文本快 20 倍以上
- 语义更明确,优化空间更大
WebAssembly 与 Native Client (NaCl)
Google 的 NaCl/PNaCl 也曾尝试在浏览器中运行原生代码,但已被 Chrome 移除。Wasm 是跨浏览器标准,拥有更广泛的生态支持。
WebAssembly 与 LLVM IR
LLVM IR(Intermediate Representation)是 LLVM 编译器基础设施的中间表示。Wasm 可以视为 LLVM IR 的一个"后端目标":
C/C++/Rust 源码 → LLVM 前端 → LLVM IR → Wasm 后端 → .wasm 文件
1.4 WebAssembly 历史
| 时间 | 事件 |
|---|---|
| 2015 年 | 四大浏览器厂商(Google、Mozilla、Microsoft、Apple)联合宣布 Wasm 项目 |
| 2017 年 3 月 | MVP(最小可行产品)在四大浏览器中发布 |
| 2019 年 12 月 | W3C 推荐标准(Recommendation) |
| 2020 年 | WASI(WebAssembly System Interface)开始发展 |
| 2021 年 7 月 | GC(垃圾回收)提案、线程提案推进 |
| 2022 年 | Component Model 提案、SIMD 提案成熟 |
| 2023 年 | Docker 宣布集成 Wasm 容器;Bytecode Alliance 推动 WASI Preview 2 |
| 2024-2025 年 | WASI Preview 2 稳定、Wasm GC 逐步在浏览器中落地 |
大事记时间线
2015 2017 2019 2020 2021 2022 2023 2024 2025
│ │ │ │ │ │ │ │ │
├───────┤ │ │ │ │ │ │ │
│ MVP │ │ │ │ │ │ │ │
│开发期 │ │ │ │ │ │ │ │
│ ├───────┤ │ │ │ │ │ │
│ │ 浏览器│ │ │ │ │ │ │
│ │ 全支持│ │ │ │ │ │ │
│ │ ├───────┤ │ │ │ │ │
│ │ │ W3C │ │ │ │ │ │
│ │ │ 标准化│ │ │ │ │ │
│ │ │ ├───────┤ │ │ │ │
│ │ │ │ WASI │ │ │ │ │
│ │ │ │ 起步 │ │ │ │ │
│ │ │ │ ├───────┤ │ │ │
│ │ │ │ │SIMD/ │ │ │ │
│ │ │ │ │线程 │ │ │ │
│ │ │ │ │ ├───────┤ │ │
│ │ │ │ │ │Component │ │
│ │ │ │ │ │Model │ │ │
│ │ │ │ │ │ ├───────┤ │
│ │ │ │ │ │ │Docker │ │
│ │ │ │ │ │ │集成 │ │
│ │ │ │ │ │ │ ├──────┤
│ │ │ │ │ │ │ │ WASI │
│ │ │ │ │ │ │ │ P2 │
1.5 WASI — WebAssembly System Interface
WASI(WebAssembly System Interface)是 WebAssembly 的系统接口标准,使得 Wasm 模块可以在浏览器之外运行,并安全地访问操作系统功能。
为什么需要 WASI?
Wasm 最初设计用于浏览器,只能调用 Web API。但社区发现 Wasm 在服务端、边缘计算、IoT 等场景也有巨大潜力。WASI 提供了标准化的系统调用接口:
┌──────────────────────────────┐
│ Wasm 应用/模块 │
├──────────────────────────────┤
│ WASI 接口(标准化) │
│ ├── 文件系统 (fd) │
│ ├── 环境变量 (environ) │
│ ├── 命令行参数 (args) │
│ ├── 时钟 (clock) │
│ ├── 随机数 (random) │
│ └── 网络 (sockets) │
├──────────────────────────────┤
│ 宿主运行时 (Wasmtime等) │
├──────────────────────────────┤
│ 操作系统 (Linux/macOS/...) │
└──────────────────────────────┘
WASI Preview 1 vs Preview 2
| 特性 | Preview 1 | Preview 2 |
|---|---|---|
| 状态 | 稳定,广泛支持 | 正式发布 |
| 接口风格 | wasi_snapshot_preview1 | Component Model WIT |
| 网络支持 | 有限 | 完善(WASI HTTP、Socket) |
| 跨组件通信 | 不支持 | Component Model |
| 典型运行时 | Wasmtime 0.x-15+ | Wasmtime 16+、WasmEdge |
1.6 适用场景
✅ 强烈推荐使用 Wasm 的场景
| 场景 | 原因 | 典型案例 |
|---|---|---|
| 图像/视频处理 | 计算密集,需要 SIMD | Squoosh、FFmpeg.wasm |
| 加密/解密 | 需要高性能、常量时间执行 | Signal Protocol |
| 游戏引擎 | 需要接近原生的渲染性能 | Unity WebGL、Unreal Engine |
| 代码编辑器 | 语法高亮、代码分析需要大量计算 | Figma、Google Earth |
| 科学计算 | 数值模拟、矩阵运算 | TensorFlow.js (Wasm 后端) |
| 边缘计算 | 冷启动快、沙箱安全 | Cloudflare Workers |
| 插件系统 | 安全沙箱、跨语言支持 | Envoy Proxy、Zed Editor |
⚠️ 可以使用但非必要的场景
| 场景 | 说明 |
|---|---|
| 普通 CRUD 应用 | JS 已经足够 |
| 简单表单验证 | 不值得引入 Wasm |
| DOM 密集型操作 | Wasm 无法直接操作 DOM |
❌ 不推荐的场景
- 纯静态页面
- 不涉及计算的展示型网站
- 团队没有系统编程经验且学习成本过高
1.7 业务场景示例
场景 1:前端图片压缩
// 使用 Wasm 实现浏览器端图片压缩,避免上传到服务器
async function compressImage(file, quality) {
const wasmModule = await WebAssembly.instantiateStreaming(
fetch('/wasm/image-compress.wasm'),
{ env: { memory: new WebAssembly.Memory({ initial: 256 }) } }
);
const { compress } = wasmModule.instance.exports;
// 读取文件到 Wasm 线性内存
const buffer = await file.arrayBuffer();
const input = new Uint8Array(buffer);
// ... 调用 compress 函数
}
场景 2:边缘计算安全验证
用户请求 → Cloudflare Worker → 加载 Wasm 模块 → 验证 JWT/签名 → 返回结果
│
├─ 冷启动 < 1ms
├─ 沙箱隔离
└─ 跨语言(Rust 编写验证逻辑)
场景 3:跨语言插件系统
宿主应用(Node.js/Go/Rust)
├── 加载插件 1(Rust → .wasm)
├── 加载插件 2(C++ → .wasm)
└── 加载插件 3(AssemblyScript → .wasm)
所有插件共享同一沙箱 API,互不干扰
1.8 WebAssembly 生态全景
┌─────────────── 编译工具链 ──────────────────┐
│ Emscripten (C/C++) │ wasm-pack (Rust) │
│ AssemblyScript │ Grain, Zig, Go ... │
└─────────────────────┬───────────────────────┘
│
┌─────────────────────▼───────────────────────┐
│ Wasm 模块 (.wasm) │
└─────────────────────┬───────────────────────┘
│
┌─────────────┼─────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 浏览器 │ │ 服务器 │ │ 边缘节点 │
│(Browser) │ │(Server) │ │(Edge) │
│ │ │ │ │ │
│ V8/Spider │ │ Wasmtime │ │ CF Worker│
│ Monkey │ │ Wasmer │ │ Fastly │
└──────────┘ └──────────┘ └──────────┘
1.9 扩展阅读
- WebAssembly 官方网站
- MDN WebAssembly 文档
- W3C WebAssembly 规范
- WebAssembly 提案追踪
- WASI 官方文档
- Bytecode Alliance
- Lin Clark — WebAssembly 入门漫画
下一章:02 - 安装与工具链 — 搭建你的 WebAssembly 开发环境。