likes
comments
collection
share

WebAssembly 前世今生

作者站长头像
站长
· 阅读数 20

一、认识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引擎中的编译过程

  1. js代码 经历 词法分析,成为token
  2. 然后经过语法分析,将token转换成AST(抽象语法树)
  3. 用解释器根据AST,生成字节码
  4. 使用JIT(just-in-time)即时编译技术,将字节码转成机器码,然后计算机就可以识别执行了

WebAssembly 前世今生

WebAssembly使用和编译流程

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

WebAssembly 前世今生

三、哪些语言可以编译为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

WebAssembly 前世今生

一个简单的例子:

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

WebAssembly 前世今生

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

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

WebAssembly 前世今生

WebAssembly 前世今生

目前已经有不少基于webAssembly开发的js库

此外,微信小程序也已经支持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%。

  • 网页版CADweb.autocad.com/login

    知名桌面端设计软件,依赖WebAssembly在浏览器中焕发生机。

  • google地球www.google.com/intl/zh-CN/…

    WebAssembly诞生前google地球只能在chrome浏览器中运行,WebAssembly帮助google地球在不同的浏览器中都可以良好运行。

六、几点说明

  1. WebAssembly被设计为JavaScript的补充和扩展,而不是替代品;
  2. WebAssembly适合在浏览器中做CPU密集型的程序运算,如视频和图像编辑、VR/AR、复杂算法等,并不是所有场景都适合用WebAssembly;
  3. WebAssembly不能直接操作DOM;
  4. WebAssembly还有很长的路要走,有些问题亟待解决,比如:它在js中的使用并不简洁、无异常处理、无垃圾回收机制等。