背景
Javascript的早期
1995 年 JavaScript 诞生。它的设计时间非常短,前十年发展迅速。
紧接着浏览器厂商们就开始了更多的竞争。
JS之所以运行慢是因为,浏览器的JS引擎是需要边解释边运行的,同时作为弱类型,在很多优化也不是很好
Javascript的发展
自从 JavaScript 诞生起到现在已经变成最流行的编程语言,这背后正是 Web 的发展所推动的。
Web 应用变得更多更复杂,但这也渐渐暴露出了 JavaScript 的问题
- 语法太灵活导致开发大型 Web 项目困难
性能不能满足一些场景的需要
针对以上两点缺陷,近年来出现了一些 JS 的代替语言
微软的 TypeScript 通过为 JS 加入静态类型检查来改进 JS 松散的语法,提升代码健壮性
- 谷歌的 Dart 则是为浏览器引入新的虚拟机去直接运行 Dart 程序以提升性能
火狐的 Asm.js 则是取 JS 的子集,JS 引擎针对 asm.js 做性能优化
不过以上尝试仍然各有优缺点,其中
TypeScript 只是解决了 JS 语法松散的问题,最后还是需要编译成 JS 去运行,对性能没有提升
- Dart 只能在 Chrome 预览版中运行,无主流浏览器支持,用 Dart 开发的人不多
-
浏览器性能优化尝试
尝试在浏览器中改善JS性能和增强功能,古往今来,在浏览器里面尝试改善 JavaScript 性能和增强功能的尝试大约都失败了。
前有 ActiveX,Java Applet,Flash,后有 Silverlight,Flex,NaCl。
WebAssembly 是各个浏览器团队的最新尝试。不过这次大家都学乖了,没人指望一个私有标准会成功,于是联合起来开发一个开放的标准。浏览器性能优化之JIT
2008年,人们称之为浏览器性能大战的时期开始了。很多浏览器加入了即时编译器,又称之为JITs。
在这种模式下,JavaScript在运行的时候,JIT 选择模式然后基于这些模式使代码运行更快。
这些 JITs 的引入是浏览器运行代码机制的一个转折点。突然之间,JavaScript 的运行速度快了10倍。
随着这种改进的性能,JavaScript 开始被用于意想不到的事情,比如使用Node.js和Electron构建应用程序。
但浏览器性能仍然有优化空间。WebAssembly应用而生
三大浏览器巨头分别提出了自己的解决方案,互不兼容,这违背了 Web 的宗旨; 是技术的规范统一让 Web 走到了今天,因此形成一套新的规范去解决 JS 所面临的问题迫在眉睫。
于是 WebAssembly 诞生了,WebAssembly 是一种新的字节码格式,主流浏览器都已经支持 WebAssembly。
和 JS 需要解释执行不同的是,WebAssembly 字节码和底层机器码很相似可快速装载运行,因此性能相对于 JS 解释执行大大提升。WebAssembly正在发展
现在 WebAssembly 可能是的另一个转折点。
2018年11月13日,Mozilla 在其官方博客上发表了一篇文章指出当今世界四大主流浏览器 Firefox,Chrome,Safari,Edge,都已经支持了名为 WebAssembly 的新技术。定义
字节码标准
WebAssembly 并不是一门编程语言,而是一份字节码标准。
- 需要用高级编程语言编译出字节码放到 WebAssembly 虚拟机中才能运行 。
浏览器厂商需要做的就是根据 WebAssembly 规范实现虚拟机。
技术方案
WebAssembly 是一种可以使用非 JavaScript 编程语言编写代码并且能在浏览器上运行的技术方案。
二进制格式
WebAssembly 可以被看做是通过浏览器运行的某种高效的开放的二进制格式。
- 并且可以和 JavaScript 环境互通。
特点
可移植
WebAssembly 是一种可移植的二进制格式,它不依赖于具体的浏览器平台。高效
WebAssembly 被设计为针对 Size 和 Load Time 进行优化的格式,可以在各个硬件平台上以 native speed 运行。安全
WebAssembly 是运行在沙盒内的,甚至可以和当前的 JavaScript 虚拟机共享一套环境,并且也遵守浏览器各种跨域不跨域的规章制度。开放
WebAssembly 是开放标准,不受某一家厂商控制(Oracle你听到了吗)。并且被设计为可以和 JavaScript API 和 Context 交互。对比
与 JavaScript 对比,WebAssembly 又具备如下特点:体积小
由于浏览器运行时只加载编译成的字节码,一样的逻辑比用字符串描述的 JS 文件体积要小很多加载快
由于文件体积小,再加上无需解释执行,WebAssembly 能更快的加载并实例化,减少运行前的等待时间。兼容性好
WebAssembly 是非常底层的字节码规范,制订好后很少变动,就算以后发生变化,也只需在从高级语言编译成字节码过程中做兼容。
可能出现兼容性问题的地方在于 JS 和 WebAssembly 桥接的 JS 接口。原理
计算机机器码
电子计算机都是由电子元件组成,为了方便处理电子元件只存在开闭两种状态,对应着 0 和 1,也就是说计算机只认识 0 和 1,数据和逻辑都需要由 0 和 1 表示,也就是可以直接装载到计算机中运行的机器码。
机器码可读性极差,因此人们通过高级语言 C、C++、Rust、Go 等编写再编译成机器码。
由于不同的计算机 CPU 架构不同,机器码标准也有所差别,常见的 CPU 架构包括 x86、AMD64、ARM, 因此在由高级编程语言编译成可自行代码时需要指定目标架构。WebAssembly
WebAssembly 字节码是一种抹平了不同 CPU 架构的机器码。
WebAssembly 字节码不能直接在任何一种 CPU 架构上运行, 但由于非常接近机器码,可以非常快的被翻译为对应架构的机器码。
因此 WebAssembly 运行速度和机器码接近,这听上去非常像 Java 字节码。LLVM IR
LLVM能实现到不同 CPU 架构机器码的生成。
LLVM 还实现了 LLVM IR 到 WebAssembly 字节码的编译功能,也就是说只要高级语言能转换成 LLVM IR,就能被编译成 WebAssembly 字节码。
目前能编译成 WebAssembly 字节码的高级语言有
语言 | 简介 |
---|---|
AssemblyScript | 语法和 TypeScript 一致,对前端来说学习成本低,为前端编写 WebAssembly 最佳选择 |
c\c++ | 官方推荐的方式 |
Rust | 语法复杂、学习成本高,对前端来说可能会不适应 |
Kotlin | 语法和 Java、JS 相似,语言学习成本低 |
Golang | 语法简单学习成本低 |
通常负责把高级语言翻译到 LLVM IR 的部分叫做编译器前端。
把 LLVM IR 编译成各架构 CPU 对应机器码的部分叫做编译器后端。
现在越来越多的高级编程语言选择 LLVM 作为后端,高级语言只需专注于如何提供开发效率更高的语法同时保持翻译到 LLVM IR 的程序执行性能。