WebAssembly(Wasm)通俗讲解
一句话
WebAssembly (Wasm) 是运行在浏览器里的「二进制高性能代码」 JS 是解释型脚本;Wasm 是编译后的二进制指令,速度接近原生 C/C++。
类比
- JavaScript:像 Python,边解释边跑,性能一般
- WebAssembly:像 exe 程序,提前编译好,浏览器虚拟机直接执行,计算速度飞快
能干什么
- 浏览器里跑重型计算:图像、视频解码、游戏、3D、AI 模型
- 语言跨平台:C/C++/Rust/Go →编译→Wasm,在浏览器、Node.js、Cloud‑Wasm 容器运行
- 和 JS 互相调用:JS 负责页面交互,Wasm 负责重活计算
Wasm 不能直接操作 DOM,只能通过 JS 做桥梁
运行流程
C/C++/Rust源码 → 编译器(Emscripten) → .wasm二进制文件
↓
浏览器下载wasm → 实例化 → JS调用wasm函数
极简可运行示例(JS + Wasm)
不需要装复杂的 C 编译器,直接手写一份 wasm 文本 (.wat)
.wat是 WebAssembly 可读文本格式,可以编译成.wasm
1. 新建文件 add.wat
(module
;;导出一个add加法函数,接收两个i32整数,返回和
(func $add (param $a i32) (param $b i32) (result i32)
local.get $a
local.get $b
i32.add
)
(export "add" (func $add))
)
含义:导出加法函数 add(a,b)=a+b
2. 把 wat 转为 wasm
在线转换工具(不用本地装工具): webassembly.studio 或者 wat2wasm 命令(wabt 工具)
wat2wasm add.wat -o add.wasm
3.HTML 页面加载 wasm,JS 调用它 (index.html)
<!DOCTYPE html>
<html>
<body>
<script>
//读取并实例化wasm文件
fetch("./add.wasm")
.then(res => res.arrayBuffer())
.then(bytes => WebAssembly.instantiate(bytes))
.then(result => {
//拿到导出的add函数
const {add} = result.instance.exports;
//调用Wasm里面的加法函数
const sum = add(10, 20);
console.log("Wasm计算结果:",sum); //输出 30
})
</script>
</body>
</html>
启动一个本地 web 服务器打开 html(不能直接双击打开文件,浏览器跨域限制)
npx serve .
打开页面,控制台打印:Wasm计算结果: 30 👉加法运算并不是 JS 算的,而是 WebAssembly 二进制代码计算出来
常用开发路线对比
表格
| 语言 | 编译器 | 输出 Wasm |
|---|---|---|
| Rust | wasm‑pack | .wasm(前端最主流) |
| C/C++ | Emscripten(emcc) | .wasm + js 胶水文件 |
| Go | Go 内置编译器 | .wasm |
现实业务例子
- Figma、抖音网页版视频解码、游戏引擎、浏览器运行大模型 (LLM),底层大量使用 Wasm
Rust + WebAssembly 完整 Demo(加法示例)
1、环境准备
1.1 安装 Rust
官网:Install Rust - Rust Programming Language 安装完校验:
rustc --version
cargo --version
1.2 安装 wasm-pack(Rust→Wasm 打包工具)
cargo install wasm-pack
2、新建项目
cargo new wasm-add-demo
cd wasm-add-demo
修改 Cargo.toml
[package]
name = "wasm-add-demo"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
3、Rust 源码 src/lib.rs
use wasm_bindgen::prelude::*;
// 导出函数,给JavaScript调用
#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[wasm_bindgen]
pub fn multiply(a:i32,b:i32)->i32{
a*b
}
4、编译打包生成 Wasm
wasm-pack build --target web
编译成功后,输出产物在:pkg/文件夹 里面包含:
wasm_add_demo_bg.wasm:二进制 wasm 文件wasm_add_demo.js:胶水 JS 模块
5、编写前端 index.html(和 pkg 文件夹同级)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Rust‑Wasm Demo</title>
</head>
<body>
<script type="module">
//导入wasm胶水模块
import init, {add,multiply} from './pkg/wasm_add_demo.js';
//初始化wasm
await init();
//调用Rust写的函数
const res1 = add(100, 200);
const res2 = multiply(6,7);
console.log("add(100,200) =", res1);
console.log("multiply(6,7) =", res2);
</script>
</body>
</html>
6、启动本地 web 服务器(必须!不能双击打开 html)
npx serve .
浏览器打开控制台,输出:
add(100,200) = 300
multiply(6,7) = 42
目录结构
wasm-add-demo/
├─pkg/ # wasm编译产物
├─src/
│ └─lib.rs # Rust源代码
├─Cargo.toml
└─index.html # 前端页面
补充知识点
#[wasm_bindgen]宏 = Rust 与 JS 之间的桥梁,负责类型转换--target web:输出原生 ES 模块,适合浏览器直接加载- 如果要给 Vue/React 项目使用,目标参数改为
--target bundler
一、Wasm 在浏览器 Network (网络面板) 特征
✅ 完全可以抓到!
1. 抓到的文件
就是 .wasm 二进制文件,例如: wasm_add_demo_bg.wasm
Network 面板特征
-
文件后缀 :
.wasm -
Response‑Header Content‑Type:
Content-Type: application/wasm
这是 Wasm 独有的 MIME 类型,非常标志性
- 预览 (Preview) 面板 : 乱码 因为它是二进制文件,不是文本,不能像 JS、JSON 一样可读。
- 请求发起者:一般由你的 js 胶水文件发起获取
二、Network 面板截图对照(文字描述)
打开浏览器 F12 → Network →筛选 All / Fetch/XHR 你会看到三条请求:
index.html→ htmlwasm_add_demo.js→ js 胶水文件wasm_add_demo_bg.wasm→ wasm 二进制本体
💡小提示:
.wasm请求不是 XHR,它是通过fetch()下载,所以在 Fetch/XHR 分类里面可以看见。
三、Wasm 和普通 JS 在网络层面区别
表格
| 项目 | JavaScript(.js) | WebAssembly(.wasm) |
|---|---|---|
| Content‑Type | application/javascript |
application/wasm |
| 文件内容 | 可读文本代码 | 二进制字节,预览乱码 |
| 加载方式 | 浏览器直接解析执行 | 下载后交给WebAssemblyAPI 实例化 |
| 网络抓包能否看到源码 | 能直接看到源码 | 抓到也看不懂,是编译后的二进制 |
四、加载完整网络时序(你 Rust 示例的请求流程)
浏览器请求index.html
↓
html加载js模块 pkg/wasm_add_demo.js
↓
js代码执行 init() →内部发起fetch下载 *.wasm二进制文件
↓
浏览器拿到wasm二进制 → WebAssembly.instantiate()实例化
↓
JS就可以调用Rust导出的 add() multiply() 函数
五、怎么判断一个网站有没有用 WebAssembly?
两种方法:
- 网络面板法 (F12‑Network) :看有没有后缀
.wasm,Content‑Type:application/wasm - 调试器 (Debugger / 源代码面板) :看有没有
.wasm文件
六、容易踩坑的现象
- wasm 文件被缓存了,刷新看不到请求 解决:勾选网络面板上方「Disable cache(禁用缓存)」,再刷新页面
- 双击打开 html 本地文件,浏览器禁止加载 wasm (跨域 / 本地文件限制) 所以必须启动本地 web 服务器
npx serve .
七、补充:抓包拿到 .wasm 之后能不能逆向?
可以反编译,但是看不到原始 Rust 源代码,只能得到可读性很差的 Wasm 汇编文本 (.wat)。 工具:wasm2wat(wabt 工具集),将二进制还原成可读 wat 文本。