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.wasm3.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 --version1.2 安装 wasm-pack(Rust→Wasm 打包工具)
cargo install wasm-pack2、新建项目
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 文本。