JavaScript
1995年javascript诞生,而且诞生的很快。
这货前10年迅速发展,紧接着就开始浏览器大战,都来抢占市场份额。
当时的互联网也不太发达,应用也没那么复杂,所以很多浏览器厂商还没考虑到js执行的效率问题。
JIT即时编译
为了提升js执行的效率,很多浏览器加入了JIT,让js的执行速度提升了几十倍。
详细点说就是给 JavaScript 引擎添加了一个新的武器,称为监视器(也称为分析器)。
该监视器在 JavaScript 运行时监控代码,并记录代码片段运行的次数以及使用了哪些数据类型。
如果相同的代码行运行了几次,这段代码被标记为 “warm”。
如果运行次数比较多,就被标记为 “hot”。
被标记为 “warm” 的代码被扔给基础编译器,只能提升一点点的速度。被标记为 “hot” 的代码被扔给优化编译器,速度提升的更多。
它是即时编译,也就是在js代码执行期间编译的。因为 JavaScript 是动态类型语言(弱类型),相同的代码在多次执行中都有可能因为代码里含有不同的类型数据被重新编译。这样会消耗时间,导致JIT时效。
所以,很多时候JIT能否生效取决于开发者的代码是如何写的。
ASM.js
2013年,ASM.js由Mozilla提出,是JavaScript的一个子集,可以更大程度的优化以提高执行速度。
既然是子集,那么其实还是js代码。但ASM.js是强类型的,语法上利用了一些标注让JS的变量成为强类型。
intValue = f1() | 0; // 利用或运算(|)标记函数f1返回值为int32整数 floatValue = +f2(); // 用加号(+)标记函数f2返回值为双精度型浮点
特殊的语法格式
function MyAsmModule(stdlib, foreign, heap) { "use asm"; // "use asm"来告诉JS引擎这个函数采用asm.js编译器解析执行 module body... return { // 返回向外暴露的函数接口 export1: f1, export2: f2 }; } var result = MyAsmModule({}, {}, null).export1(); // 调用函数export1
ASM.js 没有垃圾回收机制,所有内存操作都由程序员自己控制,ASM.js 通过 TypedArray 直接读写内存。
另外它只提供了两种数据类型:32位带符号整数和64位带符号浮点数。其他数据类型,比如字符串、布尔值或者对象,ASM.js 一概没有,只能编码成内存中一段连续的32位整数等方式来供ASM进行处理。它们都是以数值的形式存在,保存在内存中,通过 TypedArray 调用。
WebAssembly和ASM.js具有相同的作用,都可以将C/C++代码转成javascript引擎可以运行的代码。
ASM.js生成的是javascript代码,而WebAssembly生成的是WASM格式的二进制字节码,理论上WebAssembly速度更快。
最大的好处就是所有浏览器都支持 ASM.js,不会有兼容性问题。
NaCI
2011年 Google 创造了 Native Client,目的是想将现有的C/C++应用无痛的跨平台到web浏览器上运行,还可以构建如音视频、图片处器多媒体应用、大型游戏、深度学习和区块链相关的密集计算类web应用。
但该技术有个很大的弊端,需要为每种不同的处理器架构分别单独编译对应版本的NaCI二进制模块文件。
这种方式就很不方便啦,也不符合开业软件的便携特性,可移植性较差,如果由于历史原因导致某一种型号的处理器架构已经不被使用,那么所有该架构下的NaCI模块都不可用了。
PNaCI
NaCI 升级版本(Pro Native Client),解决了NaCI的可移植性问题,不依赖具体的硬件架构,一次编译,多处运行。
基于LLVM
生成具有抽象中间比特码格式的模块,这种模块不依赖具体的处理架构,可以随意的分发。
浏览器加载比特码到内存中,使用AOT转译,生成当前处理器架构能够执行的机器码,然后就可以被浏览器执行。
PNaCI性能很高,和C++基本一致,但只能运行在Chrome浏览器中。当时Opera Mozilla都没有支持这个技术。
另外应用场景过窄,高校的音频处理、视频处理、高性能计算等,需求场景很少,再加上开发难度大,需要用C/C++,开发成本过高。在16年团队解散, 18年不再支持PNaCi应用。