背景

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 开发的人不多
  • Asm.js 语法太简单、有很大限制,开发效率低

    浏览器性能优化尝试

    尝试在浏览器中改善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 的程序执行性能。