WebAssembly

WebAssembly(Wasm)通俗讲解

一句话

WebAssembly (Wasm) 是运行在浏览器里的「二进制高性能代码」 JS 是解释型脚本;Wasm 是编译后的二进制指令,速度接近原生 C/C++

类比

  • JavaScript:像 Python,边解释边跑,性能一般
  • WebAssembly:像 exe 程序,提前编译好,浏览器虚拟机直接执行,计算速度飞快

能干什么

  1. 浏览器里跑重型计算:图像、视频解码、游戏、3D、AI 模型
  2. 语言跨平台:C/C++/Rust/Go →编译→Wasm,在浏览器、Node.js、Cloud‑Wasm 容器运行
  3. 和 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          # 前端页面

补充知识点

  1. #[wasm_bindgen] 宏 = Rust 与 JS 之间的桥梁,负责类型转换
  2. --target web:输出原生 ES 模块,适合浏览器直接加载
  3. 如果要给 Vue/React 项目使用,目标参数改为 --target bundler

一、Wasm 在浏览器 Network (网络面板) 特征

完全可以抓到!

1. 抓到的文件

就是 .wasm 二进制文件,例如: wasm_add_demo_bg.wasm

Network 面板特征

  1. 文件后缀 : .wasm

  2. Response‑Header Content‑Type:

    Content-Type: application/wasm

这是 Wasm 独有的 MIME 类型,非常标志性

  1. 预览 (Preview) 面板 : 乱码 因为它是二进制文件,不是文本,不能像 JS、JSON 一样可读。
  2. 请求发起者:一般由你的 js 胶水文件发起获取

二、Network 面板截图对照(文字描述)

打开浏览器 F12 → Network →筛选 All / Fetch/XHR 你会看到三条请求:

  1. index.html → html
  2. wasm_add_demo.js → js 胶水文件
  3. 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?

两种方法:

  1. 网络面板法 (F12‑Network) :看有没有后缀.wasmContent‑Type:application/wasm
  2. 调试器 (Debugger / 源代码面板) :看有没有.wasm文件

六、容易踩坑的现象

  1. wasm 文件被缓存了,刷新看不到请求 解决:勾选网络面板上方「Disable cache(禁用缓存)」,再刷新页面
  2. 双击打开 html 本地文件,浏览器禁止加载 wasm (跨域 / 本地文件限制) 所以必须启动本地 web 服务器 npx serve .

七、补充:抓包拿到 .wasm 之后能不能逆向?

可以反编译,但是看不到原始 Rust 源代码,只能得到可读性很差的 Wasm 汇编文本 (.wat)。 工具:wasm2wat(wabt 工具集),将二进制还原成可读 wat 文本。

相关推荐
@福者1 小时前
C++ QT 入门
开发语言·c++·qt
风吹心凉1 小时前
第2天|拆解ReAct Prompt:Thought、Action、Observation与信息流
javascript·react.js·prompt
今天AI了吗1 小时前
【AI】一文讲清 RAG:从大模型局限到企业级知识库落地流程
前端·javascript·人工智能·python·深度学习·机器学习·easyui
长友cy1 小时前
Qt官方示例BluetoothLowEnergyGame源码阅读
开发语言·qt
草青工作室1 小时前
java-不携带Token也能“打“自己的接口:一个绕开网关鉴权、用 URL 直接调度 SpringMVC 方法的轻量级定时任务方案
java·开发语言
shmily麻瓜小菜鸡1 小时前
JavaScript / TypeScript 易踩坑知识点完全指南 -假值(Falsy Values)完全指南
开发语言·javascript·typescript
工边页字1 小时前
Electron应用的8种防护方式
前端·javascript·electron
Coodor1 小时前
信创系统基于QT5操作NFC读写器
开发语言·qt·智能卡·nfc读写器·yw-607hc