2018-11-10 11:35:56
JavaScript在网页编程中一直具有统治性的地位,在网页进化的历程中,JavaScript的性能提升经历了不断地改革。
它原本的执行速度并不算快,其中一次转折比较大的点在2008年,许多浏览器引入 Just-in-time (JIT,文章后面还会提到)编译器,大大提高了JavaScript的执行效率,这也让JavaScript开始能在后端领域被使用。
随着网页内容的丰富,在网页中实现3D游戏、音视频处理得到了越来越多的关注,但在网页中如何提供更好的速度和体验感一直是一个挑战。
JavaScript作为一种弱类型语言,前端的逻辑在不断的壮大,需要更多的限制来更好的帮助程序员之间的协作。
所以就出现了一些想要解决的问题:
- 语法过于灵活。
- 性能。
语法过于灵活
针对于这一点,市面上出现了TypeScript,为JS加入静态类型检查。
但这样最后还是要编译成JS,对性能没有提升。
曾经の解决方法
- 谷歌研制出了Dart,给浏览器引入新的虚拟机去直接运行Dart程序以提升性能,但只限于谷歌浏览器,用的人不多。
- 火狐推出了asm.js,它是JS的子集,让引擎针对asm.js做性能优化。asm.js的语法太简单,限制多。
什么是WebAssembly
WebAssembly是一种新的字节码格式。
和JS需要解释执行不同的是,WebAssembly 字节码和底层机器码很相似,可快速装载运行,因此性能相对于 JS 解释执行大大提升。
用高级编程语言编译出字节码放到 WebAssembly 虚拟机中才能运行, 浏览器厂商需要做的就是根据 WebAssembly 规范实现虚拟机。
由于非常接近机器码,可以非常快的被翻译为对应架构的机器码。
WebAssemblyの优点
- 体积小。
浏览器只加载编译好的字节码,一样的逻辑比用JS体积要小很多。 - 加载快。
体积小,无需解释执行。 - 兼容性问题少。
WebAssembly制订好后很少变动。可能出现兼容性问题的地方在于JS和WebAssembly桥接的接口规范。
为什么它比JavaScript更快?
首先,JavaScript运行消耗的时间有以下几个任务:
- Parsing:源代码→解释器可运行的代码所花的时间;
- Compiling+optimizing:基线编译器和优化编译器花的时间(P.S:一些优化编译器不在主线程运行,所以不包括)
- Re-optimizing: JIT发现优化假设错误,丢弃优化代码所花的时间。包括重优化的时间、抛弃并返回到基线编译器的时间。
- Execution:执行代码的时间
- Garbage collection:垃圾回收,清理内存的时间
这些任务是交叉执行的,比如正在进行解析过程时,其他一些代码正在运行,而另一些正在编译。
这几个阶段不是按顺序来的,有部分代码可能在1阶段,有的可能在3阶段,等等。这样的规律也正是JIT带来的,也是因为这样,JS的效率才得到了提升。
WebAssembly本身就算是中间代码,不需要像JS代码一样被分解为抽象语法树后再进行转换。在代码开始被编译优化之前,也不需要知道它的类型。
并且JIT对不同的编译器做了不同的优化处理,这也是为什么一段代码,可能在谷歌浏览器运行很快,但是在其他浏览器中没这么快,而WebAssembly在这时候已经经历过优化的过程,可以省略掉这段优化的时间。在垃圾回收上,WebAssembly主要是让开发者们自己写代码去手动回收,浏览器在默认情况下都是自动进行回收,这样有时候其实没有这个检查的必要。
能编译为WebAssembly的高级语言
目前能编译成WebAssembly的高级语言有:
- AssemblyScript
语法和TypeScript一致。 - cc++
官方推荐的方式。 - Rust
语法复杂。 - Kotlin
语法和Java、JS相似。 - Golang:
语法简单。对WebAssembly还处于未正式发布阶段。
WebAssemblyの展望
综上,WebAssembly非常适用于需要大量计算的场景:
- 在浏览器中处理音视频。
- dom diff用WebAssembly重写能提升性能。RN的应用性能也能提升。
- 大型3D网页游戏(白鹭引擎已经开始探索用WebAssembly)。
结语
这篇总结是我整合了网上的一些文章和资料而写成的,仅供学习和参考,谢谢。