什么是 WebAssembly

WebAssembly(简称 Wasm)是一种低级的二进制指令格式,让 C/C++/Rust 等语言编译出来的程序能直接在浏览器里跑。它不是要取代 JavaScript,而是补上 JS 不擅长的那一块:计算密集型任务。浏览器把它当成一种新的、可高度优化的运行目标。

Wasm 不是"另一种语言",而是让现有高性能语言能进浏览器的一条通道。
本文核心知识点
  • 二进制体积小、加载与解析快。
  • 接近原生计算性能远高于 JS。
  • 安全隔离在沙箱里运行,不碰 DOM。
  • 互补重计算交给 Wasm,界面仍用 JS。
WebAssembly 配图:蓝色渐变背景上发光的立方体代码模块,旁边浏览器窗口、齿轮与代码符号,表示模块被编译后在浏览器运行
编译后的模块在浏览器中运行——这就是 Wasm 的核心画面。

它为什么比 JS 快

JS 是动态类型语言,运行时要做大量类型推断与优化;Wasm 是接近机器码的二进制,加载即编译,没有解释的开销,执行效率接近原生。简单说:JS 像边翻译边跑,Wasm 像提前编译好直接跑。对海量循环、图像处理、加密这类纯计算任务,差距可以达到几倍到几十倍。

要理解这个差距的来源,关键在类型。JS 里一个变量今天装数字、明天可能装字符串,引擎要边跑边猜;Wasm 模块在编译时就把每一处的类型、内存布局定死了,运行时直接按机器指令执行,没有解释和 JIT 预热的开销。所以同样一段浮点密集的循环,Wasm 往往能跑到接近原生的速度,而 JS 要花很久才能被引擎优化到位。

典型应用场景

适合用 Wasm 的场景:大型在线编辑器(如把 Photoshop 搬到网页)、视频编解码、图像滤镜、科学计算、游戏引擎、把已有的 C/C++ 库移植到浏览器。判断标准很简单:如果这段逻辑用 JS 算起来明显卡顿,就该考虑 Wasm。纯 DOM 操作、页面逻辑,老老实实用 JS。

在浏览器里加载与调用

浏览器原生支持 .wasm 模块,用 WebAssembly.instantiate 加载,导出的函数就能直接调用。下面是最简化的加载流程。

// 加载一个编译好的 wasm 模块并调用导出函数
WebAssembly.instantiateStreaming(fetch('add.wasm'))
  .then(({ instance }) => {
    const sum = instance.exports.add(3, 4);
    console.log('结果是', sum);   // 7
  });

实际项目里一般用 Rust/Go 工具链把代码编译成 wasm,再由 JS 胶水层调用,手写 wasm 很少见。

JS 与 Wasm 如何交换数据

Wasm 有自己的线性内存(一块字节缓冲区),它不能直接碰 DOM。复杂数据(比如一段文字、一张图片)要在 JS 侧把数据写进这块内存,再让 Wasm 读取;返回结果也是一段二进制,由 JS 解释。这种边界拷贝的成本,是选型时要权衡的——数据反复跨边界传,优势会被抵消。

因此经验是:让 Wasm 一次吞进尽可能多的数据、在内部把计算全部做完,再一次性把结果交回 JS,而不是每算一步就来回传一次。图像处理就是典型——把整张图片的像素数组一次性拷给 Wasm,在里面跑完滤镜算法,再把结果数组拷回来显示,这样跨边界的次数最少,收益最大。