WebAssembly 并不总是更快
理解 WASM 的优势、边界与调用成本,避免为了技术标签把简单工具做得更重。
WebAssembly 常被概括为“浏览器里的原生速度”。这句话指出了它的潜力,却省略了最关键的条件:运行什么、数据怎样进入模块、模块多大,以及用户设备是否已经为下载和初始化付出更多时间。
对一个静态工具站来说,WASM 是重要能力,但不应该成为默认答案。
WASM 擅长的工作
计算密集、循环明确、已有成熟原生库的任务,通常最适合迁移到 WASM。例如图片编解码、音视频处理、PDF 解析、压缩算法和加密计算。这类工作能在模块内部处理大块连续内存,并减少频繁跨越 JavaScript 边界。
另一个实际优势是代码复用。一个经过多年验证的 Rust 或 C/C++ 库,可以在浏览器中继续使用,而不必完整重写为 JavaScript。
成本藏在哪里
浏览器必须先下载、编译并实例化 .wasm 文件。对于一次只做几毫秒的字符串转换,一个数 MB 的模块很可能让总体体验更慢。移动设备上的解析与内存压力也不能用桌面开发机的结果代替。
JavaScript 和 WASM 之间的调用不是免费的。频繁传递短字符串或小对象,需要编码、复制或管理共享内存。如果算法每一步都回到 JavaScript 更新界面,边界成本可能吃掉计算收益。
更合适的方式是批量传入数据,让模块完成一个足够大的工作单元,再返回紧凑结果。
用总耗时做判断
不要只测核心函数。用户经历的是完整链路:
下载模块 + 初始化 + 读取文件 + 数据转换 + 算法执行 + 生成结果
至少比较三组数据:首次访问、缓存后的再次访问,以及低端移动设备。若 WASM 把算法从 200 毫秒缩短到 80 毫秒,却增加 1.5 秒的首次加载,它可能只适合延迟加载,而不是进入首页公共包。
线程与跨源隔离
WASM 多线程通常依赖 SharedArrayBuffer,页面需要设置 COOP 和 COEP 等跨源隔离响应头。这个安全模型会约束第三方资源:广告、分析或嵌入内容若没有兼容响应头,可能无法加载。
因此,有广告的内容站不应随意在整个域名开启跨源隔离。更清楚的架构是:普通单线程工具与内容页保持常规策略;确实需要多线程的大型工具放到独立子域名,并单独评估广告兼容性。
一条实用决策路径
先实现最小 JavaScript 版本,测量真实瓶颈。如果工作主要耗在 DOM、网络或文件读取,换成 WASM 不会解决问题。只有核心计算占据明显时间,再比较现有 WASM 库与自行编译的维护成本。
引入时还要回答:
- 模块能否按需加载并缓存?
- 是否提供取消、超时与错误恢复?
- 峰值内存能否覆盖目标移动设备?
- 开源许可证是否允许当前分发方式?
- 失败时是否有 JavaScript 回退或清楚提示?
技术的价值来自解决瓶颈,不来自出现在架构图里。
WASM 让浏览器能承担过去必须交给服务器或桌面软件的任务,这是它真正令人兴奋的地方。保持测量与克制,才能让这项能力转化为更快、更私密的工具,而不是更大的下载包。