什么是WebAssembly?
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有效载荷通过JavaScript传递给客户端。
WebAssembly的设计考虑到了许多性能密集型的、基于浏览器的用例:游戏、音乐流、视频编辑、CAD、加密和图像识别,仅举几例。
一般来说,在确定你的特定WebAssembly用例时,把重点放在这三个方面是有指导意义的。
- 已经存在于一种目标语言中的高性能代码。例如,如果你有一个已经用C语言编写的高速数学函数,并想把它纳入一个网络应用程序,你可以把它作为一个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中,我们也有类似的问题,而且正在以类似的方式解决(源码图支持)。请看该项目关于计划中的工具支持的说明。
JavaScript WebAssembly 应用程序的应用
经DZone MVB的Traven West许可,发表于DZone。请看这里的原文。