一、认识WebAssembly
WebAssembly的诞生
2010年,创业失败的Alon Zakai博士加入了Firefox的开发商Mozilla公司。虽然加入了Mozilla公司,但他还是对创业时用C++开发的游戏念念不忘,他想把C++开发的游戏运行在浏览器里,又不想用JS重写,于是他希望把C++编译为JavaScript。
有了这个想法之后,Alon就开始利用业余时间开发Emscripten,试图将C++编译成js。
2011年,Emscripten正式发布。Emscripten利用LLVM(构架编译器的框架系统)将C++编译为字节码,然后再将字节码编译为JavaScript,成功地将C++游戏运行在浏览器中。Emscripten最开始编译出的目标称为asm.js,asm.js是javaScript的子集,它移除了javascript中的动态类型和垃圾回收机制,所以在编译的过程中会跳过一些语法分析,因此执行起来也更快。
正式因为asm.js是javaScript的子集,因此它不能使用javaScript的完整功能,在使用的过程中存在着各种各样的问题。于是Emscripten的开发团队构想将Emscripten的结果编译为一个二进制模块,然后在浏览器中增加一个对应的虚拟机,这样既摆脱了JavaScript的束缚,也可以优化编译速度和编译结果的体积。于是WebAssembly迎来了它的重要发展期。
2015年,4个浏览器产商(Firefox, Chrome, Safari, Edge)达成合作,4个竞争者宣布联手开发WebAssembly。
2017年,Firefox、Chrome、Safari、Edge相继支持WebAssembly。
2019年,W3C发布WebAssembly正式标准,WebAssembly成为继HTML、CSS、JavaScript之后第4种Web语言。
那么,WebAssembly是什么?
- 是一个可移植、体积小、加载快并且兼容 Web 的全新格式,是除了 JavaScript 以外,另一种可以在浏览器中执行的编程语言;
- 是一种低级的类汇编语言,具有紧凑的二进制格式,可以接近原生的性能运行;
- 设计的目的不是为了手写代码,而是为诸如 C、C++和 Rust 等低级源语言提供一个高效的编译目标;
- 可以与 JavaScript 一起工作。
WebAssembly 具有的巨大意义
它提供了一条途径,以使得以各种语言编写的代码都可以以接近原生的速度在 Web 中运行。在这种情况下,以前无法以此方式运行的客户端软件都将可以运行在 Web 中。
二、WebAssembly的工作原理
开发者以更接近于人类语言的程序语言进行编写代码,但计算机处理器只能理解机器语言。因此,你编写的代码必须转换为机器码才能运行。这个将源代码转译为机器码的过程,称为编译。
我们提到WebAssembly比 javaScript运行快、性能好主要就是体现在编译过程上。
javaScript在V8引擎中的编译过程
-
js
代码 经历 词法分析,成为token
-
然后经过语法分析,将
token
转换成AST(抽象语法树) -
用解释器根据AST,生成字节码
-
使用JIT(just-in-time)即时编译技术,将字节码转成机器码,然后计算机就可以识别执行了

WebAssembly使用和编译流程
- 源代码->Wasm:开发者提前将开发好的C/C++等程序编译为Wasm二进制文件;
- Wasm文件验证:Wasm文件中的字节码还不是机器码,它只是浏览能够理解的一组虚拟指令,浏览器会验证其合法性;
- Wasm编译为机器码:由于代码在第一步中已经经过优化,变量类型也都是预知的,所以浏览器可以轻松的将Wasm编译为机器码。

三、哪些语言可以编译为WebAssembly
-
C和C++,你可以使用Emscripten来将它编译到 WebAssembly,MDN示例:developer.mozilla.org/zh-CN/docs/…
-
Rust正致力称为WebAssembly的首选编程语言,MDN示例:developer.mozilla.org/zh-CN/docs/…
-
AssemblyScript是一种新的编译器,它接受TypeScript并将其转换为WebAssembly。github.com/AssemblyScr…
-
TeaVM是一个将java转译到javaScript的工具,现在也可以生成WebAssmebly了。
-
Go语言官方支持将其编译为WebAssmebly。github.com/golang/go/w…
-
Pyodide是一个python项目,支持将Python编译为WebAssembly。
-
Blazor是微软的实验性项目,用于将C#编译为WebAssembly。
-
此外,webAssembly还支持文本格式进行编辑,一般使用S-expressions汇编语言进行编辑,然后使用对应的工具编译为wasm文件。developer.mozilla.org/zh-CN/docs/…
GitHub上维护了一个语言列表(github.com/appcypher/a…),其中的语言可以编译到WebAssembly,或将其VM放入到WebAssembly,这个列表页指明了这些语言对WebAssembly的支持程度。
四、WebAssembly在浏览器中的使用场景
-
图片/视频编辑
-
游戏:
- 需要快速打开的小游戏
- 资源量很大的游戏。
-
图像识别、图片压缩
-
视频直播
-
VR和虚拟现实
-
科学可视化和仿真
-
高度复杂的算法
-
……
在浏览器中webAssembly适合做cpu密集型的程序运算。当然,webAssembly也可以脱离浏览器运行,如在服务端执行不可信任的代码、游戏分发服务等。
五、前端如何使用webAssmebly?
我们可以将wasm文件当做一个模块导入javaScript程序中,浏览提供了webAssembly API。可参考:MDN-WebAssmebly

一个简单的例子:
1.假如我们有一段c++代码如下,我们的目的是在js中调用其中的add方法。

编译为wasm文件:在Wat 中看到wasm导出了一个函数”_Z3addii“,就是c++中的add函数。

2.在js中加载wasm模块,使用webAssembly api实例化wasm模块,并与js进行交互。


目前已经有不少基于webAssembly开发的js库
- tesseract.js:在前端实现图片文字识别
- ffmpeg.wasm:在前端进行视频编辑、视频转码
- pocketsphinx.js:实现录音功能
- squoosh:这是一款谷歌浏览器插件,主要用来做图片压缩
此外,微信小程序也已经支持webAssembly。小程序提供了WXWebAssembly API,它类似于 Web 标准 WebAssembly,能够在一定程度上提高小程序的性能。
webAssembly在国际大厂中的实际应用
-
eBay
的条形码扫描:www.infoq.cn/article/vc*…eBay 在原生应用中有专门的 C++ 库用于条形码的扫描,在 H5 中利用开源 JavaScript 库 BarcodeReader 做了一个带条形码扫描功能的Web版本。 问题是它只有在 20% 的时间表现良好。 剩余的 80% 的时间运行非常缓慢,准确率也不高。
最终的解决方案是通过 wasm ,将原有的 c++ 库引入,以及业界十分有名的、基于 C 语言编写的开源条形码扫描库 ZBar 引入,再加上原本的 js 库,三者协助,最终识别率达到了 100%。
-
网页版CAD:web.autocad.com/login
知名桌面端设计软件,依赖WebAssembly在浏览器中焕发生机。
-
google地球:www.google.com/intl/zh-CN/…
WebAssembly诞生前google地球只能在chrome浏览器中运行,WebAssembly帮助google地球在不同的浏览器中都可以良好运行。
六、几点说明
- WebAssembly被设计为JavaScript的补充和扩展,而不是替代品;
- WebAssembly适合在浏览器中做CPU密集型的程序运算,如视频和图像编辑、VR/AR、复杂算法等,并不是所有场景都适合用WebAssembly;
- WebAssembly不能直接操作DOM;
- WebAssembly还有很长的路要走,有些问题亟待解决,比如:它在js中的使用并不简洁、无异常处理、无垃圾回收机制等。