JavaScript 用 30 年走完的路,WebAssembly 用 5 年就走完了。
引子:一个让 JavaScript 汗颜的数字
2017 年,Mozilla 的工程师在 Chrome DevTools 里跑了一个实验:用 C++ 写一个计算斐波那契数列的函数,分别用 JavaScript 和 WebAssembly 编译后执行。
结果:Wasm 版本比 JavaScript 快约 20 倍。
这个数字在当时的社区里炸开了锅。在此之前,"浏览器里能跑接近原生速度的代码"这件事,被认为是痴人说梦。
然后发生的事情证明,这个数字不是魔法,而是一个新时代的开始。
一、WebAssembly 是什么?
1.1 官方定义
WebAssembly(缩写 Wasm)是一种为栈式虚拟机构设计的二进制指令格式。
翻译成人话:Wasm 是一种浏览器能直接执行的机器码格式,它快得离谱,且不依赖任何特定编程语言。
它的设计目标不是取代 JavaScript,而是与 JavaScript 协同工作——JavaScript 处理 UI 逻辑和动态交互,Wasm 处理计算密集型任务。两者在同一个网页里各司其职。
1.2 它的"辈分"其实很高
WebAssembly 的历史,比大多数人以为的要长得多:
- 2015年:Mozilla 首次提出 asm.js 的概念——一种可以被浏览器优化的 JavaScript 子集,这被认为是 Wasm 的前身
- 2017年:Wasm 正式发布 MVP(最小可行产品)版本,Chrome、Firefox、Safari、Edge 同步支持
- 2019年:W3C 正式成立 WebAssembly Working Group,Wasm 成为官方 Web 标准
- 2022年:Wasm Component Model 和 WASI(WebAssembly System Interface)规范进入成熟期
- 2024-2026年:Wasm 开始从浏览器走向服务器、边缘、物联网——它正在"脱浏览器化"
1.3 二进制意味着什么?
传统 Web 应用的工作流是:
源代码(TypeScript/JS) ↓ 编译 JavaScript 文本(ASCII/UTF-8) ↓ HTTP 传输 浏览器下载(体积大,传输慢) ↓ 解析 浏览器 JIT 编译(边运行边优化) ↓ 执行Wasm 的工作流是:
源代码(C/C++/Rust/Go) ↓ 编译 Wasm 二进制(.wasm 文件) ↓ HTTP 传输 浏览器下载(体积小,传输快) ↓ 解码(极快,二进制直接解析) ↓ 执行二进制格式的解码(Decoding)速度远快于 JavaScript 的解析(Parsing)+ 编译(Compilation)。以一个 10MB 的模块为例:
| 指标 | JavaScript | WebAssembly |
|---|---|---|
| 文件体积 | 10 MB | 约 4 MB |
| 解析/解码耗时 | 约 500-2000ms | 约 50-200ms |
| JIT 编译 | 需要(边跑边优化) | 可选(更直接的优化路径) |
二、技术原理:Wasm 是怎么跑起来的?
2.1 虚拟机的栈式设计
WebAssembly 运行在一个基于栈的虚拟机上,而不是基于寄存器的虚拟机(如 x86/ARM)。这个设计选择非常重要:
- 栈式 VM 的指令更短:因为操作数不需要编码进指令里,指令只描述"操作",操作数从栈顶取
- 更容易跨平台:栈的结构不依赖任何 CPU 架构,一条 Wasm 指令在 x86 和 ARM 上行为完全一致
- 更容易验证安全性:在执行前就可以完整验证所有操作,不会出现越界内存访问
一条简单的加法指令在 Wasm 中看起来是这样的(文本格式,.wat):
;; 加法: 从栈顶取两个值,相加,结果压回栈顶 (i32.add (i32.const 3) (i32.const 5)) ;; 结果: 栈顶值为 8编译器负责把高级语言翻译成这种栈式指令,虚拟机负责执行它。
2.2 内存模型:线性内存
Wasm 运行时有一块线性内存(Linear Memory),是一个可增长的字节数组(ArrayBuffer)。
// JavaScript 端可以操作 Wasm 内存constmemory=newWebAssembly.Memory({initial:10,maximum:100})// initial: 初始 10 页(每页 64KB),即 640KB// maximum: 最大 100 页,即 6.4MBWasm 代码在这块内存里读写数据,JavaScript 可以同步读写同一块内存——这是两者互相操作数据的主要方式。
2.3 与 JavaScript 的互操作
Wasm 和 JavaScript 的关系不是"取代",而是"协作":
// 1. 加载 Wasm 模块constresponse=awaitfetch('compute.wasm')constbuffer=awaitresponse.arrayBuffer()const{instance}=awaitWebAssembly.instantiate(buffer)// 2. 调用 Wasm 函数constresult=instance.exports.compute_square(7)// 返回 49// 3. Wasm 函数可以反过来调用 JavaScript 函数// 通过 import 机制,Wasm 拿到 JavaScript 的函数引用后即可调用这段互操作代码只有几行,但背后的设计非常精妙:Wasm 可以导入(import)任何 JavaScript 函数作为自己的外部依赖,而 JavaScript 也可以拿到 Wasm 导出的(export)函数直接调用。
三、性能真相:Wasm 到底有多快?
3.1 benchmark 实测数据
以下数据来自多个社区 benchmark 和 Mozilla/WASM 官方测试的综合结果(不同场景数据差异较大,仅供参考):
| 场景 | JavaScript 基准 | WebAssembly | 提速倍数 |
|---|---|---|---|
| 斐波那契数列(递归) | 基准 | ~18x faster | 18x |
| SHA-256 加密哈希 | 基准 | ~10x faster | 10x |
| 图像处理(滤镜/卷积) | 基准 | ~8-15x faster | 12x |
| PDF 渲染(poppler/wasm) | 基准 | ~5x faster | 5x |
| 物理模拟(Box2D) | 基准 | ~8x faster | 8x |
| JSON 序列化(simdjson) | 基准 | ~3-5x faster | 4x |
| 矩阵乘法 | 基准 | ~20x faster | 20x |
3.2 性能来源的三层解剖
第一层:编译时优化
JavaScript 是动态类型语言,JIT(Just-In-Time)编译器在运行时才做优化,而且需要收集足够多的运行时类型信息才能启用激进优化。Wasm 在编译阶段就完成了类型检查和优化,运行时直接执行优化后的代码。
第二层:SIMD 并行化
2022 年正式支持的SIMD(Single Instruction Multiple Data)是 Wasm 性能大幅提升的关键技术之一。SIMD 允许一条指令同时操作多个数据:
// 没有 SIMD:16 次运算for(leti=0;i<16;i++)c[i]=a[i]*b[i]// 有 SIMD:1 次运算(一条指令处理 16 个数据)// SSE/AVX/NEON 级别的并行,在 Wasm 中可通过 SIMD 指令集实现第三层:垃圾回收优化
JavaScript 的 GC(垃圾回收)是-stop-the-world 的——GC 时所有代码都要暂停。Wasm 的内存管理更精细,线性内存模型让内存分配和释放的开销极低,没有 GC 暂停带来的卡顿。
3.3 Wasm 不可能完美的地方
Wasm 有明确的边界,以下场景它帮不了你:
DOM 操作:Wasm 不能直接操作 DOM,必须通过 JavaScript 来修改页面元素。这就是为什么 Figma 的架构是"渲染引擎用 Wasm,UI 框架用 React"——Wasm 计算,JS 画图。
网络请求:Wasm 本身没有网络 API,需要通过 JavaScript 或 WASI 来发起网络请求。
启动时间:Wasm 模块的下载和实例化有固定开销,对于小规模计算任务,JavaScript 可能反而更快。
四、应用场景:谁在用 Wasm?
4.1 Figma:在线设计工具的性能天花板
Figma 是在线工具里 Wasm 用得最极致的案例。它的整个渲染引擎用 C++ 编写,编译为 Wasm,在浏览器里跑出了接近桌面应用的速度。
这意味着什么?
- 一个需要专业设计软件的团队,不需要安装任何东西,打开浏览器就能用
- 多人实时协作,每次操作在毫秒级同步
- 在性能较弱的设备上,依然流畅
Figma 在 2022 年被 Adobe 以约 200 亿美元收购,Wasm 是其技术护城河的关键一环。
4.2 Google Earth:3D 渲染进入浏览器
Google Earth 的 Web 版本用 Wasm 驱动 3D 渲染引擎,突破了 JavaScript 的性能瓶颈,实现了在浏览器里流畅渲染整个地球的 3D 模型。
4.3 浏览器端 AI 推理:Qwen3-ASR-0.6B
这是 2026 年最令人震撼的 Wasm 应用之一:阿里开源的 Qwen3-ASR-0.6B 模型(语音识别),可以在浏览器里通过 Wasm 直接运行。
用户录音 → Web Audio API → Wasm 推理 → 实时文字输出 整个过程:不需要服务器,不上传数据,完全在本地完成隐私保护 + 零服务器成本 + 毫秒级响应——这是 Wasm + 端侧 AI 的完美结合。
4.4 PDF 处理:PDF.js 的 Wasm 进化
Mozilla 的 PDF.js 是浏览器里最流行的 PDF 渲染库。2024 年后,核心渲染引擎迁移到 Wasm,PDF 解析速度提升了约 5 倍。
4.5 游戏引擎:Unity 和 Unreal 的 Web 版
Unity WebGL 导出基于 Wasm,Unreal Engine 的 Web 版本(via Emscripten)也跑在 Wasm 上。浏览器里跑 3D 游戏,在 2026 年已经不是噱头。
五、WASI:Wasm 走出浏览器的关键一跃
5.1 为什么 WASI 比 Wasm 本身更重要
WASI(WebAssembly System Interface)是一套标准化的系统 API 接口规范。有了 WASI,Wasm 模块可以像本地程序一样访问文件系统、网络、系统时钟——而这一切都是跨平台的。
没有 WASI 的 Wasm:只能在浏览器里运行,需要 JavaScript 提供所有系统能力。
有 WASI 的 Wasm:可以在任何有 WASI 运行时的平台上运行——服务器、边缘节点、物联网设备。
5.2 WASI 的设计哲学
WASI 的设计哲学是最小权限原则(Principle of Least Privilege):
每个 Wasm 模块在启动时,必须声明自己需要哪些系统能力(文件访问、网络访问、时钟等),运行时只授权被声明的部分。
// Rust + wasm32-wasi 编译时指定权限// 假设这是一个需要文件读取能力的程序usestd::fs;// 这个程序被限制为只能读取 /data 目录下的文件// 即使用户恶意注入代码,Wasm 模块也无法访问其他目录这意味着:即使 Wasm 模块被攻击,攻击者的破坏范围也被严格限制在已授权的接口内。这是 Wasm 在服务器端安全的核心原因。
5.3 服务端 Wasm:一个新的运行时格局
2026 年,Wasm 的最重要战场已经不在浏览器里。
| 场景 | 传统方案 | Wasm + WASI |
|---|---|---|
| 插件系统 | V8 沙箱 / 进程隔离 | Wasm 沙箱(启动快 100 倍) |
| 边缘计算 | Docker 容器 | Wasm 模块(冷启动 1ms vs 容器 100ms) |
| 函数计算 | Lambda/云函数 | Wasm 边缘函数(成本更低) |
| 数据库 UDF | Lua/Python | Wasm UDF(多语言统一) |
Cloudflare Workers(全球最大的边缘计算平台之一)已经全面支持 Wasm;Fastly、AWS Lambda@Edge 也在跟进。
六、开发实战:如何写一个 Wasm 模块?
6.1 用 Rust 写 Wasm(推荐方式)
Rust 是目前写 Wasm 的首选语言——它的类型系统和所有权模型让内存安全代码编写变得自然,而wasm-pack和wasm-bindgen工具链让 Rust 与 JavaScript 的交互变得极其顺畅。
安装工具链:
# 安装 Rustcurl--proto'=https'--tlsv1.2-sSfhttps://sh.rustup.rs|sh# 添加 wasm32 编译目标rustup targetaddwasm32-unknown-unknown# 安装 wasm-pack(构建 + 发布)cargoinstallwasm-pack编写 Rust 代码:
// src/lib.rsusewasm_bindgen::prelude::*;/// 计算整数平方#[wasm_bindgen]pubfnsquare(x:i32)->i32{x*x}/// 计算阶乘(非递归,防止栈溢出)#[wasm_bindgen]pubfnfactorial(n:i32)->i64{letmutresult:i64=1;letmutcurrent=n;whilecurrent>1{result*=current;current-=1;}result}编译为 Wasm:
wasm-pack build--targetweb这会生成:
pkg/my_project_bg.wasm:二进制 Wasm 模块pkg/my_project.js:JavaScript 胶水层代码
在网页中使用:
<scripttype="module">importinit,{square,factorial}from'./pkg/my_project.js'awaitinit()console.log(square(7))// 49console.log(factorial(20))// 2432902008176640000</script>6.2 用 C/C++ 写 Wasm(Emscripten)
Emscripten 是最老牌的 Wasm 编译工具链,适合已有 C/C++ 代码需要迁移到 Web 的场景。
# 安装 Emscripten(需要 Docker 或 Linux/macOS)# https://emscripten.org/docs/getting_started/downloads.html# 编译 C 代码为 Wasmemcc my_algorithm.c\-O3\-sWASM=1\-sEXPORTED_FUNCTIONS='["_square", "_factorial"]'\-ooutput.js6.3 用 Go 写 Wasm(新手友好)
Go 1.21+ 内置了 Wasm 支持,门槛最低:
// main.gopackagemainimport("fmt""syscall/js")funcmain(){// 注册 square 函数到 JavaScript 全局对象js.Global().Set("square",js.FuncOf(func(this js.Value,args[]js.Value)interface{}{x:=args[0].Int()returnx*x}))// 防止主 goroutine 退出<-make(chanbool)}编译:
GOOS=jsGOARCH=wasm go build-ofib.wasm main.go七、生态现状:2026 年的 Wasm 生态
7.1 工具链成熟度
| 工具 | 用途 | 成熟度 |
|---|---|---|
| Rust + wasm-pack | 最推荐的 Wasm 开发方式 | ⭐⭐⭐⭐⭐ |
| Emscripten (C/C++) | 遗产 C/C++ 代码迁移 | ⭐⭐⭐⭐ |
| Go (GOOS=js) | 快速原型 | ⭐⭐⭐ |
| AssemblyScript | TypeScript → Wasm | ⭐⭐⭐ |
| Pyodide | Python 科学计算 | ⭐⭐⭐ |
| wasm-bindgen | Rust-JS 互操作 | ⭐⭐⭐⭐⭐ |
| Wasmtime | 生产级 WASI 运行时 | ⭐⭐⭐⭐ |
| Wasmer | 通用 Wasm 运行时 | ⭐⭐⭐⭐ |
7.2 关键里程碑
- 2022年:SIMD 支持正式稳定,Wasm 性能再上一层楼
- 2023年:Wasm Component Model 进入草案阶段——不同语言写的 Wasm 模块可以互相调用
- 2024年:Wasm Threads(共享内存多线程)支持主流浏览器
- 2025年:Wasm GC(垃圾回收支持)让高级语言(Scala/Kotlin/OCaml)更容易编译为 Wasm
- 2026年:Wasm 在边缘计算和 AI 推理领域全面落地
八、Wasm 的局限与未来
8.1 当前的主要局限
1. 工具链碎片化
不同语言到 Wasm 的编译链成熟度差异极大。Rust Wasm 生态很完善,但 Scala 或 Kotlin 还需要更多工作。Component Model 正在解决这个问题,但还需要时间。
2. 调试体验仍不理想
虽然 Chrome DevTools 已经支持 Wasm 调试(source map 支持),但体验远不如 JavaScript 调试流畅。Wasm 的二进制格式和栈式 VM 模型让断点调试比 JS 复杂得多。
3. 包体积
Rust 编译出的 Wasm 二进制,即使经过wasm-opt优化,也可能偏大(几十 KB 到几 MB)。这对首屏加载有影响,需要配合 HTTP/2 和压缩(brotli)使用。
4. DOM 操作的天然瓶颈
Wasm 永远需要 JavaScript 来操作 DOM,这是架构层面的限制,不是 bug。
8.2 未来趋势
趋势一:Wasm 成为"可移植性"的新标准
Docker 的创始人 Solomon Hykes 曾说:“如果 2008 年就有 Wasm + WASI,我们根本不需要创建 Docker。” 这句话正在变成现实——Wasm 的跨平台性和安全性,让它成为比容器更适合函数计算和边缘计算的运行时。
趋势二:AI 模型 Wasm 化加速
随着 llama.cpp、Qwen 等模型向 Wasm 迁移,"浏览器端运行大模型"正在从实验变成现实。这会催生一批全新的隐私优先 AI 应用。
趋势三:Component Model 统一多语言生态
Wasm Component Model 允许不同语言编译出的 Wasm 模块直接互相调用——Rust 模块可以调用 Go 模块,Go 模块可以调用 Python 模块,全部通过标准接口。2026 年这项规范正在走向成熟。
趋势四:Wasm 系统编程
WASI 0.3 规范正在让 Wasm 有能力替代轻量级系统进程,执行更复杂的系统级任务。这是 Wasm 的终极野心——成为比 Docker 更轻量、比进程更安全的通用运行时。
结语
WebAssembly 的故事,最初被定义为"让浏览器跑得快一点"的技术方案。
但它真正做到的,远不止于此。
当一个 Qwen3-ASR 模型在浏览器里安静地完成语音识别,不需要任何服务器,不需要任何数据传输——这一刻,Wasm 做的事情不是"让浏览器快一点",而是重新定义了 Web 应用能做多远。
当 Cloudflare Workers 用 Wasm 模块处理全球数百万请求,冷启动时间从 100ms 降到 1ms——这一刻,Wasm 做的事情不是"优化服务器",而是重新定义了计算资源的边界在哪里。
当一个用 Rust 写的 Wasm 模块在浏览器里调用了 Go 写的 Wasm 模块——这一刻,Wasm 做的事情不是"兼容多语言",而是重新定义了什么是跨平台。
这就是 WebAssembly。它从浏览器出发,正在走向整个计算世界。
而这个过程,才刚刚开始。