历史原因

第一次和第二次浏览器大战主要都是Internet Explorer和Netscape以及衍生出的Firefox进行,微软一直都是占据优势的。2008年Google推出Chrome浏览器,成为世界上最流行的浏览器,才算是结束了浏览器大战。
Google Chrome为什么能够脱颖而出呢,除了对Web标准更友善的支持外,卓越的性能是其中相当重要的因素,而浏览器性能之争的本质则体现在JavaScript引擎。此前,JavaScript引擎的实现方式经历了遍历语法树到字节码解释器等较为原始的方式,将每条源代码翻译成相应的机器码并执行,并不保存翻译后的机器码,使得解释执行很慢。2008年9月,Google发布了V8 JavaScript引擎。V8被设计用于提高Web浏览器中JavaScript的执行性能,通过即时编译JIT(Just-In-Time)技术,在执行时将JavaScript代码编译成更为高效的机器代码并保存,下次执行同一代码段时无需再编译,使得JavaScript获得了几十倍的性能提升。
然而,JavaScript是个无类型(untyped,变量没有类型)的语言,这直接导致表达式c=a+b有多重含义:

  • a、b均为数字,则算术运算符+表示值相加;
  • a、b为字符串,则+运算符表示字符串连接;

表达式执行时,JIT编译器需要检查a和b的类型,确定操作行为。若a、b均为数字,JIT编译器则将a、b确认为整型,而一旦某一变量变成字符串,JIT编译器则不得不将之前编译的机器码推倒重来。由此可见,JavaScript的无类型特性建立在消耗大量性能代价的基础之上。即便JIT编译器在对变量类型发生变化时已进行相应优化,但仍然有很多情况JavaScript引擎未进行或无法优化,例如for-of、try-catch、try-finally、with语句以及复合let、const赋值的函数等。

由此可见,JavaScript的无类型是JavaScript引擎的性能瓶颈之一,改进方案有两种:一是设计一门新的强类型语言并强制开发者进行类型指定;二是给现有的JavaScript加上变量类型。

微软开发的TypeScript属于第一种改进方案。它是扩展了JavaScript特性的语言,包含了类型批注,编译时类型检查,类型推断和擦除等功能,TypeScript开发者在声明变量时指定类型,使得JavaScript引擎能够更快将这种强类型的语言编译成弱类型。
看看第二种方案:

function add(a, b){
    a =a | 0;
    b =b | 0;
    return a+b | 0
}

代码1表示带有两个参数(a和b)的JavaScript函数,和通常JavaScript代码不同的地方在于a=a | 0及b=b | 0,以及返回值后面均利用标注进行了按位OR操作。这么做的优点是使JavaScript引擎强制转换变量的值为整型执行。通过标注加上变量类型,JavaScript引擎就能更快地编译。

既然增加变量类型能够提升Web性能,有没有办法将静态类型代码例如C/C++等转换成JavaScript指令的子集呢?上面的这段代码恰恰是作为JavaScript子集的asm.js,由代码2的C语言编译而来:

int add(int a, int b){
    return a+b;
}

事实上,为了解决这个问题,Mozilla和chrome都各自独立开发过asm.js和Portable Native Client(PNaCl)。然而,无论是asm.js或现有PNaCl的解决方案,都面临着一些缺陷(例如1KB的C源码编译生成asm.js后的大小有480KB)或其他浏览器不支持的窘境,而2016年10月对Chromium问题跟踪代码的评论更是表明,Google Native Client小组已被关闭。

作为Web浏览器性能和代码重用的解决方案,asm.js及PNaCl都没能被普遍接受,那么有没有上述表格中的特性全部占优,且跨厂商的解决方案呢?
WebAssembly旨在解决这个问题。

什么是WebAssembly

WebAssembly社区小组于2015年4月成立,其使命是“为Web设计一种全新的、可移植的、能够高效加载及易于编辑的轻量级格式,以促进跨浏览器协作”。
WebAssembly(简称Wasm)是一种新的适合于编译到Web的,可移植的,大小和加载时间高效的格式。这是一个新的与平台无关的二进制代码格式,目标是解决JavaScript性能问题。这个新的二进制格式远小于JavaScript,可由浏览器的JavaScript引擎直接加载和执行,这样可节省从JavaScript到字节码,从字节码到执行前的机器码所花费的即时编译JIT(Just-In-Time)时间。 作为一种低级语言,它定义了一个抽象语法树(Abstract Syntax Tree,AST),开发人员可以以文本格式进行调试。

需要了解的是,WebAssembly不是将C/C++等其他语言编译到JavaScript,更不是一种新的编程语言。

什么是Asm.js

Asm.js是一个JavaScript的一个严格的子集,可以被用来作为一个底层的、高效的编译器目标语言。asm.js提供了一个类似于C/C++虚拟机的抽象实现,包括大型二进制堆、整型和浮点运算、高阶函数定义、函数指针等语法特性。具体来说,就是通过VM(如Emscripten)把一些本地代码(如C语言)生成的VM字节码(bytecode)翻译成前述严格子集的JS代码得以在Web上运行,并通过浏览器的支持,得到性能优化。

既然有了Asm.js,为什么还要发展webassembly?

  1. asm是由Mozilla独自开发的,主流浏览器并不支持,而webassembly是Google, Microsoft,Mozilla等公司一起合作开发推出的
  2. asm.js 是文本,WebAssembly 是二进制字节码,因此webAssembly比asm更快,更小
  3. 另外WebAssembly最终将从JS中分离出来,成为一个相对独立的编译器目标语言,这样可以不必为了本地代码的运行,而在JS中引入太多内容,将来Wasm和JS会是分工合作的关系。
  4. asm.js编译速度不够快,尤其是在移动端

WebAssembly如何工作

目前WebAssembly需要通过JavaScript加载和编译。主要包括以下四个步骤:

  1. 加载wasm字节码。
  2. 将wasm字节码编译为模块。
  3. 实例化模块。
  4. 运行函数。

WebAssembly的使用场景

作为asm.js的下一代改进版,WebAssembly使用了JavaScript中一个非常受限的指令子集,该子集最适合作为C编译器的编译目标。WebAssembly不包含JavaScript对象,也不直接访问文档对象模型(Document Object Model,DOM)。从本质上来讲,WebAssembly只允许对类型数组进行算术运算和操作。
一些初步样例表明,使用wasm实现的斐波那契数生成算法比对应的JS实现性能上更优,有超过350%的性能提升。
目前,WebAssembly只是在简单模仿JS的功能,但人们计划扩展WebAssembly的使用场景,以处理JS中难以处理的事情,同时不增加语言的复杂度。比如,人们计划使WebAssembly默认支持SIMD(Single Instruction,Multiple Data,单指令流多数据流)、线程、共享内存等等功能。
许多流行视频游戏编辑器已经准备就绪,开始将WebAssembly技术与WebGL 2.0相结合,将部分3D功能引擎移植到这个全新平台上。你可以试一下Epic出品的Zen Garden,体验这种全新技术。

这是JavaScript的末日吗?

WebAssembly会促进JavaScript的发展,而不是导致其灭亡,它可以为Web中的关键功能带来语言上的多样性并提高性能。WebAssembly不单单给JS带来性能上的提升,同时也造福了Web浏览器。
由于WebAssembly的易用性和简单性,我们预测会有越来越多的代码从C++或Python转化为JS,甚至直接转化为WebAssembly。这意味着你不需要去学习一门全新的语言。JS虚拟机还是会存在,但对应工具会不断发展,以获取更优的性能。

WA的安全性如何,对网络威胁方面的意义

在浏览器中运行时,WebAssembly运行在一个安全的沙箱化环境中,这意味着WebAssembly与其他Web语言一样,遵守相同的同源策略和权限策略。根据维基百科的定义,同源策略可以“防止某个页面中的恶意脚本通过该页面的文档对象模型(DOM)获取其他Web页面上敏感信息的访问权限”。
这听起来是一个非常完美的解决方案。
然而,过去的很多案例表明,攻击者出于个人利益,总是能够找到一种方法来滥用或转移新技术的使用场景。比如,攻击者已经使用某些流行的开源项目或某些自制代码中的JS混淆代码,实现恶意代码隐藏并绕过杀毒软件的检测。
因此我们很容易就能预测到,WA可能会被攻击者用来实现高级混淆或加密。这个问题对训练有素的分析师来说并不是不能克服的,但对攻击工具的调试和挖掘将变得更加困难,也更加耗时。

我们需要改进Web浏览器以支持更加智能的WA调试工具。在任何情况下,浏览器都应该支持某个恶意模块的下载(因为模块需要在用户主机上运行)及反汇编,以帮助逆向研究人员分析模块的目的。否则,就像.NET一样,会有某些代码混淆器阻止人们将字节码还原为初始代码。但后者可能不是出于恶意目的,有时候是合法的,比如源代码作者希望通过这种方法保护他们的知识产权。

展望

由于主要的浏览器厂商对WebAssembly支持表现积极,并且都在实现WebAssembly的各项功能,因此在Web中高性能需求的应用例如在线游戏、音乐、视频流、AR/VR、平台模拟、虚拟机、远程桌面、压缩及加密等都能够获得接近于原生的性能。相信WebAssembly将会开创Web的新时代。

WebAssembly资源推荐

英文官网 http://webassembly.org/
中文官网 http://webassembly.org.cn/
MDN网址 https://developer.mozilla.org/zh-CN/docs/WebAssembly