随着Web网页的广泛发展,拥有JIT
技术加持后,JavaScript的执行效率大幅提升,但由于解释型语言的特点,以及动态类型的天生缺陷,在某些CPU密集计算型的应用场景下,JavaScript的性能仍然力不从心。而且有大量C/C++等编译型语言的软件和库,也有着搬到Web上执行的需求,但如果全部用JavaScript语言重写,显然代价十分巨大。
一系列原因催生出了WebAssembly
技术的诞生,先从asm.js
说起。
一 asm.js
1.1 发展历史
2011年,在Mozilla
工作的Alon Zakai
,想把自己以前开发的C++
游戏跑在浏览器里,但是又不想用JavaScript重写,就想能不能把C++
编译为JavaScript呢?于是他创建了 Emscripten 项目,用LLVM将C++
编译为字节码,再将字节码编译为JavaScript,成功地将C++
游戏跑在了浏览器。
当时Mozilla
的CTO正是JavaScript的作者Brendan Eich
,他的梦想是让Web可以运行任何应用,而Alon的项目正在实现他的梦想,于是大力支持,Emscripten
成为了公司的一个正式开源项目。
但仅仅将C++
编译为JavaScript还不够,因为性能不够好。主要原因是JavaScript是动态类型语言,JS引擎在生成机器码时,必须动态判断变量类型,这带来了大量的冗余代码,必然存在性能损耗。
Mozilla
的JS引擎工程师Luke Wagner
告诉Alon
,如果Emscripten
能生成特定的隐含类型的JS代码,他就可以通过优化JS引擎来提升性能,例如:
function add(x, y) {
a = x | 0; // 参数x为整数
b = y | 0; // 参数y为整数
return a + b | 0; // add函数的返回值也是整数
}
通过在JS代码中增加 | 0
,JS引擎就能推断出add
函数的参数和返回值都是整数,从而直接编译为整数加法,提高了机器码的执行效率。对这种语法的进一步规范化,就产生了asm.js
。
2013年,他们把100万行C++代码的虚幻游戏引擎编译为asm.js
,在浏览器中流畅的运行了3D游戏《史诗城堡》。
1.2 原理
asm.js
并不是一种新的语言,它只是一种遵守特定规范的JavaScript,本质上还是JavaScript。它可以手工编写,但可读性较差,所以通常是由 Emscripten
工具来编译生成。
它有以下两个特点。
- 变量都是静态类型
- 没有垃圾回收机制
前面说过,普通JS代码的执行流程是:JS源码 -> 解析器 转成 抽象语法树 -> 解释器 转为 字节码 -> 编译器 转为优化后的机器码 -> 执行。
在这过程中,由于JS的动态类型特征,同一变量上一次执行还是Object,下一次就可能变成String了,这导致JIT
编译过的机器码失去作用,只能重新进行编译。asm.js
约定静态类型就避免了这种情况的发生。
针对asm.js
进行优化后的JS引擎,如果发现运行的是asm.js
,便可以通过AOT静态编译的方式,将代码编译成机器码(且因为是静态类型,机器码可以得到极其优化)。当JS引擎再次执行(甚至是第一次执行)这段代码时,就可以直接使用前面编译过的机器码来执行了。
通过不断的优化,测试数据表明,asm.js
的性能可以达到原生C/C++代码的50%。在Firefox
浏览器率先支持asm.js
后,其它的Chrome、Safari、Edge等浏览器相继优化其JS引擎来执行asm.js
。
二 WebAssembly
2.1 发展历史
和普通JS代码相比,虽然asm.js
性能提升很大,但它始终是个包含JS代码的文本,JS引擎还是需要去解析和编译,那为什么不在浏览器中增加一个虚拟机,从而能直接运行字节码呢?让越多的应用跑在Web上,并且性能越好,用户花在Web上的时间就越多,这符合各家浏览器厂商的共同利益。
因此,在2015年,各大浏览器厂商联手宣布开发WebAssembly
。2017年,几大浏览器相继支持。2019年,W3C发布正式标准,WebAssembly
成为继HTML、CSS、JavaScript之后的第4种Web语言。
现在C/C++、Rust、Java等越来越多的强类型编程语言,都可以编译为WebAssembly字节码,直接运行在浏览器中。就像Java字节码一样,一次编译到处运行,借助于浏览器,从而具有了跨平台特性。
2.2 原理
严格说,WebAssembly
不是一种编程语言,而是一种可以在浏览器中直接运行的二进制格式,这种格式称为WASM
。
测试数据表明,WebAssembly
比asm.js
平均快了33.7%,且文件体积平均小了62.5%,另外WebAssembly
在编译速度、启动速度、内存使用等方面的表现也非常好。
WebAssembly
并不是要取代JavaScript,只是把更多的编程语言和应用带到Web中,且具有接近于原生的性能,是JavaScript能力的补充,使Web更加丰富和强大。
三 总结
asm.js
生成的是JavaScript代码,而WebAssembly
生成的是WASM
格式的二进制字节码,因此WebAssembly
的体积更小,运行速度更快。
asm.js
的兼容性比WebAssembly
好,因为它本身就是JavaScript
,所有浏览器都支持asm.js
的运行,当然现在主流的浏览器也都支持WebAssembly
,无需担心兼容问题。知名软件AutoCAD、Google Earth都借助于WebAssembly
技术,移植到了浏览器中。
WebAssembly
给Web带来了更多的可能性,对于CPU密集型的应用,比如音频、视频、直播、机器学习、AR、VR、游戏等,WebAssembly
既可以帮助突破性能瓶颈,也可以让其他语言的代码库得到充分利用。因此,WebAssembly的应用还刚刚开始,发展潜力巨大。