二十年来,我们只有一种可用于本机在网络浏览器中使用的编程语言:JavaScript。 第三方二进制插件的缓慢淘汰已经排除了其他语言,例如Java和Flash的ActionScript,成为Web开发的一等公民。 其他Web语言(例如CoffeeScript)仅被编译为JavaScript。
但是现在我们有了新的可能性:WebAssembly,简称WASM。 WebAssembly是一种小型,快速的二进制格式,可保证Web应用程序具有接近本机的性能。 另外,WebAssembly旨在成为任何语言的编译目标,JavaScript只是其中一种。 现在,每个主流浏览器都支持WebAssembly了 ,是时候开始认真考虑为网络编写可编译为WebAssembly的客户端应用程序了。
值得注意的是,WebAssembly应用程序并不是要取代 JavaScript应用程序,至少现在还不是。 而是将WebAssembly视为JavaScript的伴侣 。 JavaScript是灵活的,动态键入的,并通过人类可读的源代码提供,而WebAssembly是高速,强类型的,并通过紧凑的二进制格式提供。
开发人员应将WebAssembly用于性能密集型的用例,例如游戏,音乐流,视频编辑和CAD应用程序。
WebAssembly的工作方式
用W3C开发的WebAssembly,用其创建者的话来说就是“编译目标”。 开发人员不直接编写WebAssembly。 他们用自己选择的语言编写,然后将其编译成WebAssembly字节码。 然后,字节码在客户端上运行(通常在Web浏览器中),然后将其转换为本地机器代码并高速执行。
WebAssembly代码旨在比JavaScript更快地加载,解析和执行。 当Web浏览器使用WebAssembly时,仍然存在下载WASM模块并进行设置的开销,但是所有其他条件相同的WebAssembly运行得更快。 WebAssembly还提供了一个沙盒执行模型,该模型基于现在JavaScript所具有的相同安全模型。
目前,在Web浏览器中运行WebAssembly是最常见的用例,但WebAssembly的目的不只是基于Web的解决方案。 最终,随着WebAssembly规范的形成和更多功能的加入,它可能在移动应用程序,台式机应用程序,服务器和其他执行环境中变得有用。
WebAssembly用例
WebAssembly的最基本用例是编写浏览器内软件的目标。 可以使用多种语言中的任何一种编写被编译为WebAssembly的组件。 然后,最终的WebAssembly有效负载会通过JavaScript传递到客户端。
WebAssembly在设计时考虑了许多性能密集型,基于浏览器的用例 :游戏,音乐流,视频编辑,CAD,加密和图像识别,仅举几例。
更一般而言,在确定特定的WebAssembly用例时,将注意力集中在以下三个方面是有益的:
- 目标语言已存在的高性能代码。 例如,如果您已经用C语言编写了高速数学函数,并且想要将其合并到Web应用程序中,则可以将其部署为WebAssembly模块。 应用程序中对性能要求不高,面向用户的部分可以保留在JavaScript中。
- 高性能代码需要从头开始编写,而JavaScript并不理想。 以前,可能使用asm.js编写此类代码。 您仍然可以这样做,但是WebAssembly被定位为更好的长期解决方案。
- 将桌面应用程序移植到Web环境。 asm.js和WebAssembly的许多技术演示都属于此类。 WebAssembly可以为比通过HTML呈现的GUI更雄心勃勃的应用程序提供基础。 (请参阅WebDSP , Zen Garden和Tanks演示。)但这不是一个简单的练习,因为需要将桌面应用程序与用户交互的所有方式映射到WebAssembly / HTML / JavaScript等效项。
如果您现有JavaScript应用程序没有任何性能极限,那么最好在WebAssembly开发的这个阶段将其搁置。 但是,如果您需要该应用程序运行得更快,WebAssembly可能会有所帮助。
WebAssembly语言支持
WebAssembly并非直接编写。 顾名思义,它更像是一种汇编语言,是机器要使用的东西,而不是高级的,人性化的编程语言。 WebAssembly比C或Java更接近LLVM语言编译器基础结构生成的中间表示(IR)。
因此,大多数使用WebAssembly的场景都涉及用高级语言编写代码并将其转变为WebAssembly。 可以通过以下三种基本方法之一来完成此操作:
- 直接编译。 通过该语言自己的编译器工具链将源代码翻译成WebAssembly。 Rust,C / C ++,Kotlin / Native和D现在都具有从支持那些语言的编译器发出WASM的本机方式。
- 第三方工具。 该语言的工具链中没有本地WASM支持,但是可以使用第三方实用程序将其转换为WASM。 Java,Lua和.Net语言家族都具有这样的支持。
- 基于WebAssembly的解释器。 在这里,语言本身并未翻译为WebAssembly; 而是用WebAssembly编写的语言解释器运行用该语言编写的代码。 这是最麻烦的方法,因为解释器可能是几兆字节的代码,但是它允许使用该语言编写的现有代码几乎可以不变地运行。 Python和Ruby都将解释器翻译为WASM。
WebAssembly功能
WebAssembly仍处于早期阶段。 WebAssembly工具链和实现仍然比生产技术更接近概念验证。 就是说,WebAssembly的托管人着眼于通过一系列举措使WebAssembly更加有用:
垃圾收集原语
WebAssembly不直接支持使用垃圾回收内存模型的语言。 仅可以通过限制功能集或将整个运行时嵌入为WebAssembly可执行文件来支持Lua或Python之类的语言。 但是, 无论语言或实现方式如何,都有正在进行的工作来支持垃圾回收的内存模型 。
穿线
Rust和C ++等语言对线程的本地支持是常见的。 WebAssembly中缺少线程支持,这意味着无法使用这些语言编写面向WebAssembly的软件的整个类。 向WebAssembly添加线程的建议使用C ++线程模型作为其灵感之一。
大容量内存操作和SIMD
大容量内存操作和SIMD (单指令,多个数据)并行性是需要处理大量数据并需要本机CPU加速以免被阻塞的应用程序(如机器学习或科学应用程序)所必需的。 正在提议通过新的操作员将这些功能添加到WebAssembly的提议。
高级语言构造
WebAssembly正在考虑的许多其他功能直接映射到其他语言的高级构造。
- 可以在WebAssembly中模拟异常 ,但不能通过WebAssembly的指令集本机实现。 拟议的异常计划涉及与C ++异常模型兼容的异常原语,而这些原语又可以由编译为WebAssembly的其他语言使用。
- 通过引用类型,可以更轻松地传递用作对主机环境的引用的对象。 这将使垃圾收集和许多其他高级功能在WebAssembly中更易于实现。
- 尾调用 ,一种在多种语言中使用的设计模式。
- 返回多个值的函数 ,例如,通过Python或C#中的元组。
- 符号扩展运算符 ,一种有用的低级数学运算。 ( LLVM也支持这些。)
调试和性能分析工具
转译JavaScript的最大问题之一是由于无法在转译的代码和源代码之间建立关联,因此调试和性能分析很困难。 使用WebAssembly,我们有一个类似的问题,并且正在以类似的方式解决(源地图支持)。 请参阅有关计划的工具支持的项目注释。