什么是WebAssembly——下一代网络平台的解释

109 阅读8分钟

WebAssembly是一种二进制指令格式和虚拟机,为网络浏览器应用程序带来近乎原生的性能,并允许开发人员用他们选择的语言建立高速网络应用程序。

二十年来,我们只有一种编程语言可以在网络浏览器中使用。JavaScript。第三方二进制插件的缓慢死亡已经排除了其他语言,如Java和Flash的ActionScript,作为网络开发的第一类公民。其他网络语言,如CoffeeScript,只是被编译为JavaScript。

但现在我们有了一种新的可能性。WebAssembly,或简称Wasm。WebAssembly是一种小型、快速的二进制格式,承诺为网络应用提供近乎原生的性能。此外,WebAssembly被设计成任何语言的编译目标,JavaScript只是其中之一。

现在每个主要的浏览器都支持WebAssembly,是时候开始认真考虑为网络编写可以编译成WebAssembly的客户端应用程序了。

值得注意的是,WebAssembly应用程序并不是要取代JavaScript应用程序,至少现在还不是。相反,你可以把WebAssembly看作是JavaScript的一个伙伴。JavaScript是灵活的,动态类型的,并通过人类可读的源代码交付,而WebAssembly是高速的,强类型的,并通过一个紧凑的二进制格式交付。

开发人员应该考虑将WebAssembly用于性能密集型的使用案例,如游戏、音乐流、视频编辑和CAD应用。许多网络服务已经采取了这种做法,如谷歌地球Figma,一个协作绘图和制图的应用程序,即使在WebAssembly相对较新的时候,也转向了WebAssembly以减少加载时间和执行速度。

WebAssembly如何工作

WebAssembly是由W3C开发的,用它的创造者的话说是一个 "编译目标"。开发人员不直接编写WebAssembly;他们用自己选择的语言编写,然后被编译成WebAssembly字节码。然后,字节码在客户端运行--通常是在网络浏览器中--在那里它被翻译成本地机器码并高速执行。

WebAssembly代码旨在比JavaScript更快地加载、解析和执行。当WebAssembly被Web浏览器使用时,仍然有下载Wasm模块和设置它的开销。对于较大的Wasm项目,这些模块可以运行到几兆字节,所以这些延迟可能是显著的。但在其他条件相同的情况下,WebAssembly运行得更快。

WebAssembly还提供了一个沙盒执行模型,基于现在存在于JavaScript的相同安全模型。Wasm应用程序不能直接访问沙盒外的任何东西,包括它们所运行的网页的DOM。任何与机器其他部分的交互必须使用ABI,如WebAssembly系统接口(WASI)。WASI提供了对文件、网络、系统时钟和其他程序中经常需要的系统服务的控制访问。

现在,在网络浏览器中运行WebAssembly是最常见的使用情况,但WebAssembly的目的不仅仅是一个基于网络的解决方案。Wasmer项目在服务器端运行WebAssembly应用程序,与Node.js运行时在浏览器外运行JavaScript的方式基本相同。

WebAssembly的使用案例

WebAssembly最基本的使用情况是作为编写浏览器内软件的目标。编译成WebAssembly的组件可以用任何一种语言编写;最后的WebAssembly有效载荷会通过JavaScript传递给客户端。

WebAssembly的设计考虑到了许多性能密集型的、基于浏览器的用例:游戏、音乐流、视频编辑、CAD、加密和图像识别,仅举几例。

一般来说,在确定你的特定WebAssembly用例时,把重点放在这三个方面是有指导意义的:

  • 已经存在于一种目标语言中的高性能代码:例如,如果你有一个已经用C语言编写的高速数学函数,你想把它纳入一个Web应用程序,你可以把它作为一个WebAssembly模块部署。应用程序中对性能要求不高、面向用户的部分可以保留在JavaScript中。
  • 需要从头开始编写的高性能代码,在这里JavaScript并不理想:以前,人们可能使用asm.js来编写这样的代码。你仍然可以这样做,但WebAssembly正被定位为一个更好的长期解决方案。
  • 将一个桌面应用程序移植到网络环境中:asm.js和WebAssembly的许多技术演示都属于这个类别。WebAssembly可以为那些比通过HTML呈现的GUI更雄心勃勃的应用程序提供一个底层。请看WebDSP浏览器中的Windows 2000的演示,作为两个例子。

如果你有一个现有的JavaScript应用程序,没有推动任何性能的信封,在WebAssembly发展的这个阶段,最好不要管它。但是,如果你需要这个应用程序的速度更快,WebAssembly可能会有帮助。

WebAssembly语言支持

WebAssembly并不是用来直接编写的。顾名思义,它更像是一种汇编语言,供机器使用的东西,而不是一种高级的、对人友好的编程语言。WebAssembly更接近于由LLVM语言编译器基础设施生成的中间表示法(IR),而不是像C或Java。

因此,大多数使用WebAssembly的情况涉及到用高级语言编写代码,并把它变成WebAssembly。这可以通过三种基本方式完成:

  • 直接编译:通过语言本身的编译器工具链,将源代码翻译成WebAssembly。Rust、C/C++、Kotlin/Native和D现在都有支持这些语言的编译器发出Wasm的本地方法。
  • 第三方工具:语言在其工具链中没有原生的Wasm支持,但可以使用第三方工具来转换为Wasm。Java、Lua和.Net语言家族都有一些这样的支持。
  • 基于WebAssembly的解释器:在这里,语言本身并没有被翻译成WebAssembly;相反,一个用WebAssembly编写的语言解释器,运行用该语言编写的代码。这是最麻烦的方法,因为解释器可能是几兆字节的代码,但它允许用该语言编写的现有代码运行,但不改变。Python(例如,通过PyScript)和Ruby都有翻译成Wasm的解释器。

WebAssembly的特点

WebAssembly仍然处于早期阶段。WebAssembly工具链和实现仍然更接近于概念验证,而不是生产技术。也就是说,WebAssembly的监护人已经把目光投向了通过一系列的举措使WebAssembly更加有用。

垃圾收集基元

WebAssembly并不直接支持使用垃圾收集的内存模型的语言。像Lua或Python这样的语言只能通过限制功能集或将整个运行时嵌入WebAssembly可执行文件来支持。但目前正在进行的工作是支持垃圾收集的内存模型,不管是什么语言或实现

线程

对线程的本地支持在Rust和C++等语言中很常见。在WebAssembly中没有线程支持意味着整个WebAssembly目标软件的类别不能用这些语言编写。在WebAssembly中增加线程的建议是以C++的线程模型为灵感之一。

批量内存操作和SIMD

量内存操作SIMD(单指令,多数据)并行性是那些需要通过成堆的数据并需要本地CPU加速以防止窒息的应用程序的必备条件,如机器学习或科学应用程序。建议通过新的操作符将这些能力添加到WebAssembly中。

高级语言结构

许多其他正在考虑的WebAssembly的功能直接映射到其他语言的高级结构:

  • 异常可以在WebAssembly中进行模拟,但不能通过WebAssembly的指令集来实现。拟议的异常计划涉及与C++异常模型兼容的异常基元,这反过来又可以被其他编译成WebAssembly的语言所使用。
  • 参考类型使得在主机环境中作为引用使用的对象更容易传递。这将使垃圾收集和其他一些高级功能更容易在WebAssembly中实现。
  • 尾部调用这是一种在许多语言中使用的设计模式。
  • 返回多个值的函数例如,通过Python或C#中的图元。
  • 符号扩展运算符一个有用的低级数学操作。(LLVM也支持这些。)

调试和分析工具

转译的JavaScript最大的问题之一是调试和分析的困难,因为无法在转译的代码和源码之间建立联系。在WebAssembly中,我们也有类似的问题,而且正在以类似的方式解决(源码图支持)。请看该项目关于计划中的工具支持的说明。