深圳幻海软件技术有限公司 欢迎您!

什么是WebAssembly?

2023-02-28

​译者|陈峻审校|孙淑娟二十多年来,有一种编程语言一直在Web浏览器中以原生的方式被使用至今。这便是JavaScript。期间,我们见证了诸如Java和Flash的ActionScript等第三方二进制插件,从兴起到逐渐消亡。而作为另一类Web语言的CoffeeScript,最终仍然会被编译成Jav

​译者 | 陈峻

审校 | 孙淑娟

二十多年来,有一种编程语言一直在Web浏览器中以原生的方式被使用至今。这便是JavaScript。期间,我们见证了诸如Java和Flash的ActionScript等第三方二进制插件,从兴起到逐渐消亡。而作为另一类Web语言的CoffeeScript,最终仍然会被编译成JavaScript。可见,只有JavaScript才是Web开发界的王者,并骨灰级地被沿用着。

不过,我们现在有了一种新的可选项:WebAssembly(简称为Wasm)。作为一种小型且快速的二进制格式编程语言,它可以为Web应用提供接近原生的性能。此外,WebAssembly旨在成为任何语言的编译目标,而JavaScript只是目标中的一种。也就是说,鉴于每一种主流浏览器都能支持WebAssembly,我们有必要开始认真地考虑,如何编写出各种可以被编译为WebAssembly的客户端应用。

值得注意的是,WebAssembly应用程序并不打算(至少目前并没有)取代JavaScript应用程序。相反,鉴于JavaScript具有灵活、动态类型、以及源代码可读等交付特性,WebAssembly旨在提供高速、强类型,以及紧凑二进制式的交付特性。因此,WebAssembly可以被视为JavaScript的辅助“伙伴”。

在实际中,开发人员可以考虑将WebAssembly运用到诸如:游戏、音乐流、视频编辑、以及CAD应用等性能敏感型的用例中。目前,许多Web服务已经开始采用WebAssembly了。例如,为了缩短加载的时间与执行的速度,谷歌地球和协作式绘图与图表应用Figma,都采用了较新的WebAssembly。

1.WebAssemzbly的工作原理 

由W3C开发的WebAssembly,用其创建者的话来说是一个“编译的目标”。开发人员不必直接编写WebAssembly。他们可以选用自己熟悉的语言编写代码,然后编译成WebAssembly类型的字节码。字节码通常运行在客户端的Web浏览器中,并被翻译成可被高速执行的原生机器代码。

WebAssembly代码旨在实现比JavaScript更快的加载、解析和执行。当使用WebAssembly时,Web浏览器仍然存在下载Wasm模块,以及予以设置的开销。虽然对于较大的Wasm项目而言,此类模块会因为在运行过程中产生了几兆字节,而出现延迟。但是在其他同等条件的中小型项目中,WebAssembly会运行得更快一些。

同时,WebAssembly也提供了一个沙盒执行模型,该模型与JavaScript的现有安全模型非常相似。也就是说,Wasm应用程序无法直接访问到沙箱之外的任何内容,甚至是它们正在运行的网页上的DOM。因此,如果应用程序需要与系统中的其他部分进行交互,就必须使用类似WebAssembly系统接口(WASI,https://wasi.dev/)的各种ABI(应用程序二进制接口)。WASI为程序提供了常被用于文件、网络、系统时钟、以及其他系统服务的受控式访问。

目前,虽然在Web浏览器中运行WebAssembly,是其最常见的一种使用场景,但是WebAssembly远不仅仅是基于Web的解决方案。例如:Wasmer项目就可以在服务器端运行WebAssembly应用程序。这与Node.js运行时(runtime)在浏览器之外运行JavaScript的方式非常类似。

2.用例 

WebAssembly的最基本用例就是被开发者用来编写浏览器内的软件。我们可以用各种语言来编写出可以被编译成WebAssembly的组件,然后通过JavaScript,将WebAssembly的最终、有效负载传递给客户端。

如前文所述,WebAssembly在设计时就考虑到了各种性能密集型、基于浏览器的用例。其中包括:游戏、音乐流、视频编辑、CAD、加密、以及图像识别等等。总的说来,WebAssembly用例通常适合如下三个领域:

  • 已存在于目标语言中的高性能代码。例如,如果你有一个已用C语言编写的高效数学函数,并且需要将它合并到某个Web应用程序中,那么,你就可以将它部署为一个WebAssembly模块。同时,您可将该应用中,那些对于性能不太敏感的、面向用户的部分,保留为JavaScript。
  • JavaScript代码不够理想,需要从头开始编写的高性能代码。过去,开发人员会使用asm.js(http://asmjs.org/)来改写此类代码。如今,您可以通过WebAssembly来实现该目的。
  • 将桌面应用移植到Web环境中。虽然asm.js和WebAssembly都可以在技术上实现此类需求,但是WebAssembly可以提供比使用HTML呈现GUI更为基础的应用。对此,您可以查看WebDSP和浏览器中的Windows 2000这两个示例,来进一步了解其功效。

总之,WebAssembly开发往往能够达到比现有JavaScript应用程序更快的运行效果。

3.WebAssembly的语言支持 

顾名思义,WebAssembly不可被直接编写,它更像是一种汇编语言,一种供机器使用、而非高级的、用户友好的编程语言。与C或Java相比,WebAssembly更接近由LLVM语言编译器的基础结构所生成的中间代码表示(intermediate representation,IR)。

通常,大多数使用WebAssembly的场景都会涉及到使用如下三种基本方式中的一种,把那些由高级语言编写的代码,转换为WebAssembly:

  • 直接编译。通过本语言自带的编译器工具链,源代码可以被直接翻译成WebAssembly。例如:Rust、C/C++、Kotlin/Native、以及D都可以通过原生方式,从支持此类语言的编译器处,直接编译出Wasm。
  • 第三方工具。Java、Lua和.Net等语言虽然并不提供原生的、支持Wasm的工具链,但它们可以使用第三方实用程序,将代码转换为Wasm。
  • 基于WebAssembly的解释器。它并非是将现有语言的代码翻译成WebAssembly,而是用由WebAssembly编写的语言解释器,去运行代码。由于解释器本身就占有几兆字节的代码空间,因此,该方法较为臃肿。当然,它保留了那些原有语言编写的代码,在无需转换的情况下,被运行起来。例如,Python(往往是通过PyScript)和Ruby都拥有翻译成Wasm的解释器。

4.WebAssembly即将推出的功能 

不可否认,WebAssembly仍处于早期阶段。其工具链和实现,更接近于概念性的验证(proof-of-concept)。目前,WebAssembly正努力通过如下方面的举措,让其更加实用:

垃圾回收的原语(Primitives)

WebAssembly目前并不直接支持那些使用垃圾回收内存模型(garbage-collected memory model)的语言。我们只能通过限制功能集,或将整个运行时(runtime)嵌入WebAssembly的可执行文件,以支持Lua或Python等语言。当然,WebAssembly正在紧锣密鼓地研发其支持垃圾回收内存模型的功能。

线程(Threading)

对线程的原生支持,在Rust和C++等语言中十分常见。而WebAssembly缺乏对于线程的支持,就意味着那些以WebAssembly为最终目标的应用代码的整个类,我们都不能使用Rust和C++等语言来编写。目前,已有人提出使用C++线程模型,向WebAssembly添加线程。

大容量内存操作和SIMD

大容量内存操作和SIMD(单指令与多数据,single instruction, multiple data)的并行性,对于需要处理大量数据、并需要通过原生CPU加速,来防止阻塞的应用程序(如机器学习或数据科学应用)而言,是必不可少的。目前,WebAssembly正努力添加此类功能。

高级语言结构

同时,WebAssembly正在对标高级语言结构,并不断完善如下功能:

  • 异常(Exceptions)可以在WebAssembly中被模拟,但是不能通过WebAssembly的指令集被原生地实现。目前,WebAssembly正计划创建与C++异常模型相兼容的异常原语,以便被编译为WebAssembly的那些语言代码所使用。
  • 参考类型(Reference types)可以轻松地向主机环境传递被用作参考的对象。它能够使得垃圾回收和其他高级功能,更容易地在WebAssembly中实现。
  • 尾调用(Tail calls)是一种在多种语言中被用到的设计模式。
  • 能返回多个值的函数,如Python或C#中的元组(tuples,或称数组)。
  • 符号扩展运算符(Sign-extension operators),一种实用的低级数学运算。LLVM能够支持它。

调试和分析工具

如您所知,被转译的JavaScript存在着一个巨大问题:由于无法在转译代码和源代码之间建立关联,因此我们难以进行调试和分析。目前,WebAssembly正努力通过源地图支持的方式,来解决此类问题。

原文链接:https://dzone.com/articles/what-is-webassembly

译者介绍

陈峻 (Julian Chen),51CTO社区编辑,具有十多年的IT项目实施经验,善于对内外部资源与风险实施管控,专注传播网络与信息安全知识与经验;持续以博文、专题和译文等形式,分享前沿技术与新知;经常以线上、线下等方式,开展信息安全类培训与授课。​