一、JS引擎运行过程
该图显示了 JS 引擎运行程序花费的时间。
- Parsing :将源码转换成解释器可以运行的东西所用的时间。
- Compiling + optimizing:基础编译和优化编译上的时间。有一些优化编译的工作不在主线程,所以这里并不包括这些时间。
- Re-optimizing:当预先编译优化的代码不能被优化的情况下,JIT 将这些代码重新优化,如果不能重新优化那么久丢给基础编译去做。这个过程叫做重新优化。
- Execution:执行代码的时间
- Garbage collection:清理内存的时间
二、在运行过程中WebAssembly优于JS的原因
1、 请求
WebAssembly体积更小:下载执行与 JavaScript 等效的 WebAssembly 文件需要更少的时间,因为它的体积更小。
WebAssembly 设计的体积更小,可以以二进制形式表示。即使使用 gzip 压缩的 JavaScript文件很小,但 WebAssembly 中的等效代码可能更小。所以说,下载资源的时间会更少。在网速慢的情况下更能显示出效果来。
2、解析
JavaScript 源码一旦被下载到浏览器,源将被解析为抽象语法树(AST)。通常浏览器解析源码是懒惰的,浏览器首先会解析他们真正需要的东西,没有及时被调用的函数只会被创建成存根。在这个过程中,AST被转换为该 JS 引擎的中间表示(称为字节码)。
相反,WebAssembly 不需要被转换,因为它已经是字节码了。它仅仅需要被解码并确定没有任何错误。
3、编译+优化
JavaScript 是在执行代码期间编译的。因为 JavaScript 是动态类型语言,相同的代码在多次执行中有可能因为代码里含有不同的类型数据被重新编译,这样会消耗时间。
相反,WebAssembly 与机器代码更接近。例如,类型是程序的一部分。这是速度更快的一个原因:
- 编译器不需要在运行代码时,花费时间去观察代码中的数据类型,因为在开始编译时已做优化。
- 编译器不需要每次执行相同代码时,去判断数据类型是否一样。
- 更多的优化在 LLVM 最前面就已经完成了。所以编译和优化的工作很少。
4、重新优化
有时 JIT 抛出一个优化版本的代码,然后重新优化。JIT 基于运行代码的假设不正确时,会发生这种情况。例如,当进入循环的变量与先前的迭代不同时,或者在原型链中插入新函数时,会发生重新优化。
在 WebAssembly 中,类型是明确的,因此 JIT 不需要根据运行时收集的数据对类型进行假设。这意味着它不必经过重新优化的周期。
5、执行
尽可能编写执行性能好的 JavaScript。所以,你可能需要知道 JIT 是如何做优化的。然而,大多数开发者并不知道 JIT 的内部原理。即使是那些了解 JIT 内部原理的开发人员,也很难实现最佳的方案。有很多时候,人们为了使他们的代码更易于阅读(例如:将常见任务抽象为跨类型工作的函数)会阻碍编译器优化代码。
执行 WebAssembly 代码通常更快。有些必须对 JavaScript 做的优化不需要用在 WebAssembly 上。另外,WebAssembly 是为编译器设计的。意思是,它是专门给编译器来阅读,并不是当做编程语言让程序员去写的。由于程序员不需要直接编程,WebAssembly 提供了一组更适合机器的指令。根据您的代码所做的工作,这些指令的运行速度可以在10%到800%之间。
6、垃圾回收
在 JavaScript 中,开发者不需要担心内存中无用变量的回收。JS 引擎使用一个叫垃圾回收器的东西来自动进行垃圾回收处理。这对于控制性能可能并不是一件好事。你并不能控制垃圾回收时机,所以它可能在非常重要的时间去工作,从而影响性能。
WebAssembly 根本不支持垃圾回收。内存是手动管理的(就像 C/C++)。虽然这些可能让开发者编程更困难,但它的确提升了性能。
总之,这些都是在许多情况下,在执行相同任务时WebAssembly 将胜过 JavaScript 的原因。
三、WebAssembly是如何工作的
这个大脑的一部分是专注于思考,例如算术和逻辑。有一部分脑部提供短期记忆,另一部分提供长期记忆。
- 负责思考的部分是算术逻辑单元(ALU)。
- 短期储存由寄存器(Registers)提供。
- 随机存储器(或RAM)来提供长期储存能力。
编译器的“前端”将高级编程语言转换为IR。编译器的“后端”将 IR 转换成目标机器的汇编代码。
WebAssembly 和别的汇编语言是有一些不同的。所以他是一个概念机上的机器语言,不是在一个真正存在的物理机上运行的机器语言。WebAssembly 指令有时候被称为虚拟指令。它比 JavaScript 代码更快更直接的转换成机器代码,但它们不直接和特定硬件的特定机器代码对应。在浏览器下载 WebAssembly后,使 WebAssembly 的迅速转换成目标机器的汇编代码。
如果想在您的页面里上添加 WebAssembly,您需要将您的代码编译成 .wasm 文件。
四、总结
使用WebAssembly,可以更快地在 web 应用上运行代码。这里有 几个 WebAssembly 代码运行速度比 JavaScript 高效的原因。文件加载 - WebAssembly 文件体积更小,所以下载速度更快。
- 解析:解析 WebAssembly 比解析 JavaScript 要快。
- 编译和优化:编译和优化所需的时间较少,因为在将文件推送到服务器之前已经进行了更多优化,JavaScript 需要为动态类型多次编译代码。
- 重新优化: WebAssembly 代码不需要重新优化,因为编译器有足够的信息可以在第一次运行时获得正确的代码。
- 执行:执行可以更快,WebAssembly 指令更接近机器码。
- 垃圾回收:目前 WebAssembly 不直接支持垃圾回收,垃圾回收都是手动控制的,所以比自动垃圾回收效率更高。