刷掘金热榜发现 WebAssembly 又上去了,评论区一堆人说「学 WASM 得先学 Rust」,劝退了不少人。
说实话我之前也是这么想的——直到上个月做一个内部工具的时候,发现有些 npm 包底层就是 WASM,安装完直接用,完全不需要碰 Rust。今天分享 3 个我实际用过的,都是 npm install 一把梭,零 Rust 基础也能直接上手。
先说结论
| 库 | 干什么的 | 性能提升 | 上手难度 |
|---|---|---|---|
| sql.js | 浏览器里跑 SQLite | 比 IndexedDB 查询快 5-10x | ⭐ 极低 |
| @ffmpeg/ffmpeg | 浏览器里处理视频 | JS 根本做不到的事 | ⭐⭐ 低 |
| photon-wasm | 图片滤镜/裁剪/压缩 | 比 Canvas API 快 2-5x | ⭐ 极低 |
场景一:浏览器里跑 SQLite(sql.js)
做后台管理系统的时候遇到一个需求:前端要对一个几万行的 CSV 做复杂筛选和聚合。一开始用 JS 数组硬撸 filter + reduce,代码写得我自己都看不懂,而且 5 万行数据一个聚合查询要卡 3 秒。
后来想到——为什么不在浏览器里直接用 SQL?
npm install sql.js
import initSqlJs from 'sql.js';
// 初始化,需要指定 wasm 文件位置
const SQL = await initSqlJs({
locateFile: file => `https://sql.js.org/dist/${file}`
});
// 创建内存数据库
const db = new SQL.Database();
// 建表 + 导入 CSV 数据
db.run(`CREATE TABLE sales (
date TEXT,
region TEXT,
product TEXT,
amount REAL,
quantity INTEGER
)`);
// 批量插入(用事务,不然会巨慢)
db.run('BEGIN TRANSACTION');
csvData.forEach(row => {
db.run(
'INSERT INTO sales VALUES (?, ?, ?, ?, ?)',
[row.date, row.region, row.product, row.amount, row.quantity]
);
});
db.run('COMMIT');
// 现在可以用 SQL 了!
const result = db.exec(`
SELECT region,
SUM(amount) as total_sales,
COUNT(*) as order_count,
AVG(amount) as avg_order
FROM sales
WHERE date >= '2026-01-01'
GROUP BY region
ORDER BY total_sales DESC
`);
console.log(result[0].values);
// [['华东', 2847563.5, 12847, 221.6], ['华南', ...]]
5 万行数据,这个聚合查询 60ms 搞定。之前纯 JS 要 3 秒多。
踩坑点
- wasm 文件要单独加载。如果用 Vite,需要把
sql-wasm.wasm放到public目录,locateFile指向/sql-wasm.wasm - 数据库在内存里,刷新就没了。想持久化可以用
db.export()导出Uint8Array,存到 IndexedDB 或者 localStorage - 不支持并发写入。如果有 Web Worker 也在操作同一个数据库实例,会出问题。建议把 sql.js 整个跑在一个 Worker 里
// 持久化方案
const data = db.export();
const buffer = new Uint8Array(data);
localStorage.setItem('mydb', JSON.stringify(Array.from(buffer)));
// 恢复
const saved = JSON.parse(localStorage.getItem('mydb'));
const db = new SQL.Database(new Uint8Array(saved));
场景二:浏览器里剪视频(@ffmpeg/ffmpeg)
这个是真没想到的——FFmpeg 编译成了 WASM,能在浏览器里跑。
我的场景是做一个视频剪辑小工具,用户上传视频后自动截取前 30 秒作为预览。之前都是传到后端处理,现在直接前端搞定,省了一台服务器。
npm install @ffmpeg/ffmpeg @ffmpeg/util
import { FFmpeg } from '@ffmpeg/ffmpeg';
import { fetchFile, toBlobURL } from '@ffmpeg/util';
const ffmpeg = new FFmpeg();
// 加载 WASM(首次会比较慢,约 25MB)
const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm';
await ffmpeg.load({
coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),
});
// 监听进度
ffmpeg.on('progress', ({ progress }) => {
console.log(`处理进度: ${(progress * 100).toFixed(1)}%`);
});
// 写入文件到虚拟文件系统
const videoFile = document.querySelector('input[type="file"]').files[0];
await ffmpeg.writeFile('input.mp4', await fetchFile(videoFile));
// 截取前 30 秒 + 压缩
await ffmpeg.exec([
'-i', 'input.mp4',
'-t', '30', // 只要前 30 秒
'-vf', 'scale=720:-2', // 压缩到 720p
'-c:v', 'libx264',
'-preset', 'fast',
'-crf', '28',
'output.mp4'
]);
// 读取结果
const data = await ffmpeg.readFile('output.mp4');
const blob = new Blob([data], { type: 'video/mp4' });
const url = URL.createObjectURL(blob);
// 直接在页面上播放
document.querySelector('video').src = url;
踩坑点
- WASM 文件巨大。ffmpeg-core.wasm 大概 25MB,首次加载会很慢。建议做 loading 动画 + 缓存到 Service Worker
- SharedArrayBuffer 限制。多线程版本需要页面设置 COOP/COEP 响应头,很多部署环境不支持。单线程版也能用,就是慢一些:
// 单线程版本,兼容性更好 const baseURL = 'https://unpkg.com/@ffmpeg/core-st@0.12.6/dist/esm'; - 2GB 文件上限。WASM 内存限制,超过 2GB 的视频处理不了。不过前端场景一般也碰不到这个上限
- iOS Safari 有坑。部分老版本 Safari 对 WASM 内存分配有 bug,大文件处理可能崩溃。2026 年的 Safari 17+ 基本没问题了
场景三:图片处理快到飞起(photon-wasm)
Canvas API 做图片处理不是不能用,但一旦图片大一点(比如 4K),肉眼可见地卡。photon 是 Rust 写的图片处理库,编译成 WASM 后性能碾压 Canvas。
npm install @aspect-build/photon-wasm
# 或者直接用 CDN
import * as photon from '@aspect-build/photon-wasm';
// 从 Canvas 获取图片数据
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 加载图片到 canvas
const img = new Image();
img.src = 'photo.jpg';
await new Promise(resolve => img.onload = resolve);
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
// 创建 PhotonImage
const image = photon.open_image(canvas, ctx);
// 应用滤镜 —— 一行代码搞定
photon.filter(image, 'oceanic'); // 海洋风滤镜
// photon.grayscale(image); // 灰度
// photon.gaussian_blur(image, 3); // 高斯模糊
// photon.sharpen(image); // 锐化
// 调整亮度对比度
photon.alter_channel(image, 0, 20); // R通道+20
// 写回 canvas
photon.putImageData(canvas, ctx, image);
// 导出为 Blob 下载
canvas.toBlob(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'processed.jpg';
a.click();
}, 'image/jpeg', 0.9);
实测一张 4000x3000 的照片:
| 操作 | Canvas API | photon-wasm | 提速 |
|---|---|---|---|
| 灰度转换 | 180ms | 35ms | 5.1x |
| 高斯模糊 | 2400ms | 480ms | 5.0x |
| 批量滤镜(3个叠加) | 850ms | 190ms | 4.5x |
踩坑点
- npm 包名很混乱。搜 photon wasm 会找到好几个包,认准 GitHub(silvia-odwyer/photon)上的官方版本
- 内存要手动管理。
PhotonImage对象用完记得调用.free()释放 WASM 内存,不然会内存泄漏 - 不支持 HEIC 格式。苹果的 HEIC 图片需要先用其他库转成 JPEG/PNG 再处理
什么时候该用 WASM,什么时候别折腾
说实话大部分前端场景不需要 WASM。如果你只是做个 CRUD 后台,加什么 WASM 纯属给自己找事。
但这几种情况值得考虑:
- 计算密集型:大量数据处理、加解密、图片/音视频处理
- 现有 C/C++/Rust 轮子:比如 SQLite、FFmpeg,直接编译过来比用 JS 重写强一万倍
- 需要离线能力:数据库、文档解析这些在端上跑,不依赖后端
而且 WASI 0.3 刚在今年 2 月发布了,以后 WebAssembly 不只是浏览器的东西——边缘计算、Serverless 都能用。路线图里甚至有 wasi:nn 专门用来跑 AI 推理,以后在浏览器里直接跑模型可能也不是梦。
小结
说白了 WebAssembly 对前端来说就是一个性能工具箱。不需要学 Rust,不需要懂编译原理,npm install 完就能享受 native 级别的性能。
这三个库我在实际项目里都用过,sql.js 用得最多(报表系统的前端聚合),ffmpeg.wasm 偶尔用(用户端视频预处理),photon 适合需要批量图片处理的场景。
热榜在问「前端要不要学 WASM」——我觉得不用「学」它,用就行了。