WebAssembly
2023-03-24 21:29:13 阿炯

WebAssembly是一个低级编程语言,也被称为wasm,是便携式的抽象语法树,被设计来提供比JavaScript更快速的编译及执行。它让开发者能运用自己熟悉的编程语言(最初以C/C++作为实现目标)编译,再藉虚拟机引擎在浏览器内执行。WebAssembly的开发团队分别来自Mozilla、Google、Microsoft、Apple,代表着四大网络浏览器Firefox、Chrome、Microsoft Edge、Safari。2017年11月此四个浏览器都开始实验性的支持WebAssembly。在2019年12月5日,W3C制定《WebAssembly 核心规范》,其正式被认证为 Web 的标准之一。


WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications.

它是一种低级的类汇编语言,具有紧凑的二进制格式,可以接近原生的性能运行,并为诸如 C/C ++等语言提供一个编译目标,以便它们可以在 Web 上运行。它亦被设计为可以与 JavaScript 共存,允许两者一起工作。

设计与实现原则:定义一个可移植,具有大小与加载高效率的二进制格式,作为编译标的。这个编译标的必须可以被编译至常见的平台,包含移动端与物联网,并且可以善用硬件资源、有原生执行码的执行速度。

规格与实现:
    最初的MVP(Minimum Viable Product)与Asm.js有大略相等的功能,并以C/C++语言为优先;
    其他额外的特性最初集中在线程,零消耗的异常,和SIMD。这些额外的特性先以反馈和实验为主,包含C/C++以外其他语言的支持。
设计可以执行在现有的网络平台之内以及与之集成:
    保持无版本问题、特色测试、向后兼容的网络平台
    在与Javascript相同的环境中执行
    允许从Javascript中同步调用
    强化同源(Same-origin)和安全性权限政策
    允许浏览器访问相同功能的Javascript API
    定义一个可人工读取,能和二进制格式互换的纯文字格式,以支持查看源代码
设计也可以用于非浏览器的嵌入式系统
制作大平台
    为WebAssembly建置新的LLVM后端与伴随的Clang接口
    推动其他WebAssembly的编译器与工具
    激活更多有用的工具

WebAssembly是一种可以在现代浏览器中运行的新型代码,是为了能获得更好的性能优势。是一种更偏底层的二进制格式,体积小,因此加载和执行速度很快。开发者也不用直接编写 WebAssembly,而是可以通过将其他高级语言编译成为WebAssembly。Chrome 57、Edge 16、Safari 11、FireFox 52、Opera 44版本之上的浏览器都已经支持它。

WebAssembly(汇编)通常是指类似于机器代码的人类可读语言,机器代码是处理器所理解的,即一堆数字。为了在处理器上运行,每种高级编程语言都会被翻译成机器代码。不同类型的处理器架构需要不同的机器代码和不同类型的汇编。尽管名字叫 WebAssembly,但它并不完全是一种汇编语言,因为它并不适用于任何特定的机器。它适用于浏览器,当开发者交付要在浏览器中执行的最终代码时,开发者并不知道代码将在哪种机器上运行,而WebAssembly可以做到开发者底层完全无感。实际上,WebAssembly 是一种用于概念机器的语言,当浏览器下载 WebAssembly 代码时,它可以快速将其转换为任何机器的程序集。它具有易于阅读的文本格式特性(.wat),而二进制表示是实际交付给浏览器运行的内容(.wasm)。它能够让开发者将 C、C++ 或 Rust 代码之类的东西编译成所谓的 WebAssembly 模块,同时可以将其加载到 Web 应用程序中并从 JavaScript 中调用它。但是需要声明的是:WebAssembly不是 JavaScript 的直接替代品,它的设计理念是与JavaScript一起工作。

Web的优势在于它在任何地方都有效,避免下载和安装应用程序等繁琐流程,从而实现立即交付。它比直接在计算机上下载和运行二进制文件更安全,因为浏览器建立了安全机制,可以防止其中运行的代码干扰系统。同时在 Web 上共享内容也非常容易,通过URL即可实现,开发者还可以将Web内容托管在任何地方。Web是应用程序可在任何设备上访问、共享的唯一真正通用的平台,从而允许开发者维护一个单一的代码库,同时保持更新迅速。

一些特定的场景:视频游戏、视频编辑、3D 渲染或音乐制作等这些应用程序需要进行大量计算并且需要很高的性能,很难通过Javascript得到性能保障。JavaScript 最初只是一种简单的脚本语言,旨在为充满轻量级超文本文档的网络带来一些交互性。它被设计为易于学习和编写,但并不是为了速度而设计的。多年来,浏览器对它们解释 JavaScript 的方式进行了优化,从而带来了重大的性能改进。随着JavaScript变得越来越快,开发者可以在浏览器中执行的操作开始逐步扩展。新的 API 带来了交互式图形、视频流、离线浏览等功能。反之越来越多以前仅限于本机的丰富应用程序开始出现在网络上。如今用户可以轻松地从浏览器编辑文档和发送电子邮件,但在某些领域,JavaScript 的性能仍然是无法磨灭的硬伤。比如:视频游戏的性能局限一直极具挑战性,因为它们不仅要协调音频和视频,而且通常还要协调物理和人工智能,而WebAssembly 可以解决这些问题。

WebAssembly 专为速度而生,它的二进制文件比文本 JavaScript 文件小得多,从而下载速度快,特别是在低速网络场景。其解码和执行速度也更快。JavaScript 是一种动态类型语言,变量类型不必预先定义,也不需要预先编译。这使得编写代码变得容易和快速,但这也意味着 JavaScript 引擎有更多的工作要做,它必须在页面上执行时解析、编译和优化代码。解析 JavaScript 涉及将纯文本转换为称为抽象语法树 (AST) 的数据结构,并将其转换为二进制格式。WebAssembly 以二进制形式交付,解码速度更快。它是静态类型的,因此与 JavaScript 不同,引擎不需要在编译期间推测将使用什么类型。大多数优化发生在源代码编译期间,甚至在它进入浏览器之前。内存是手动管理的,就像 C、C++ 等语言一样,因此也没有垃圾收集。所有这些都提供了更好、更可靠的性能。据统计WASM二进制文件的执行时间仅比相同本机代码的执行时间慢 20%。

要在设备上运行应用程序,它必须与设备的处理器架构和操作系统兼容。这意味着需要为想要支持的每种操作系统和 CPU 架构组合编译源代码。使用 WebAssembly 只需一个编译步骤,应用程序就可以在每一种现代浏览器中运行,跨越了体系架构与操作系统。开发者不仅可以将自己的应用程序移植到 Web,还可以将现有的大量 C++ 库和开源应用程序移植到 Web。它是一种几乎所有平台都支持的语言,包括 iOS 和 Android。WebAssembly可以用作跨 Web 和移动部署的通用语言。

Emscripten 是一个开源的编译器,可以将 C/C++ 代码编译为 WebAssembly 编程语言的代码。Emscripten 的底层是基于 LLVM 编译器的,可以查看其开源的 emscripten llvm 和 emscripten clang 。

MDN-WebAssembly


W3C WebAssembly Community Group 开发的一项网络标准,对于浏览器而言,WebAssembly 提供了一条途径,让各种语言编写的代码以接近原生的速度在 Web 中运行。在这种情况下,以前无法以此方式运行的客户端软件等都将可以运行在 Web 中。其设计之初就决定和 JavaScript 一起协同运行 —— 通过 JavaScript 中的 WebAssembly API,可以把 WebAssembly 模块加载到一个 JavaScript 应用中并且在两者之间互相调用。这样可以在同一个应用中使用 WebAssembly 的高性能及 JavaScript 的高灵活性。众所周知 JavaScript 是解释型语言,相比于编译型语言需要在运行时转换,所以解释型语言的执行速度要慢于编译型语言。编译型语言和解释型语言代码执行的具体流程如下:


因为解释型语言每次执行都需要把源码转换一次才能执行,而转换过程非常耗费时间和性能,也就导致在 JavaScript 背景下,web 无法执行一些高性能应用,如图片剪辑、视频剪辑、3D 游戏等。

根据 MDN 的定义,WebAssembly 是一种运行在现代网络浏览器中的新型代码,并且提供新的性能特性和效果。可以在现代的网络浏览器中运行 - 它是一种低级的类汇编语言,具有紧凑的二进制格式,可以接近原生的性能运行,并为诸如 C/C ++ 等语言提供一个编译目标,以便它们可以在 Web 上运行。它也被设计为可以与 JavaScript 共存,允许两者一起工作。


工作原理

WebAssembly 不被解释,而是由开发者提前编译为 WebAssembly 二进制格式,如下图所示。由于变量类型都是预知的,因此浏览器加载 WebAssembly 文件时,JavaScript 引擎无须监测代码。它可以简单地将这段代码的二进制格式编译为机器码。


如果将每种编程语言都直接编译为机器码的各个版本,那么效率会很低。编译器中称为前端的部分会将所编写的代码编译为一种中间表示 (intermediate representation,IR)。创建好 IR 代码后,编译器的后端部分会接收 IR 代码,对其进行优化,然后将其转换为所需要的机器码。


由于浏览器可以在若干不同的处理器 (比如桌面计算机、智能手机和平板设备) 上运行,因此为每个可能的处理器发布一个 WebAssembly 代码的编译后版本会非常繁复。替代方法即取得 IR 代码,并通过一个专门的编译器来运行,这个编译器将 IR 代码转换为一种专用字节码并放入后缀为.wasm 的文件中。此时 wasm 文件中的字节码还不是机器码,它只是支持 WebAssembly 的浏览器能够理解的一组虚拟指令。当加载到支持 WebAssembly 的浏览器中时,浏览器会验证这个文件的合法性,然后这些字节码会继续编译为浏览器所运行的设备上的机器码。如下图



WebAssembly 被设计为 JavaScript 的一个组件,不是它的替代品。虽然有些开发者试图只用 WebAssembly 来创建整个网站,但这不是普遍情况。一般情况 JavaScript 仍然是更好的选择。

模块内部


模块中不同段的含义说明:


编译器负责生成 WebAssembly 模块的段,并将它们按照适当顺序放置。

所有的段都是可选的,因此可能存在空模块。

如果指定了已知段,那么它们只能出现一次并且要按照特定顺序出现。

自定义段可以放置在已知段之前、之间或之后,用于指定不适用已知段的数据。

哪些语言可用来创建 WebAssembly 模块

现在 WebAssembly 的最小可行性版本(Minimum Viable Product,MVP)还没有垃圾回收(garbage collection,GC),他限制了一些语言的使用。GC 作为一种后 MVP 功能正在开发中,实现之前,有几种语言正在试验 WebAssembly 支持,方式是将自己的 VM 编译到 WebAssembly,或者在某些情况下将自己的垃圾回收器包含进去。以下语言正在试验或已经完成 WebAssembly 支持:
1.C 和 C++
2.Rust 正致力于成为 WebAssembly 的首选编程语言。
3.AssemblyScript 是一种新编译器,它用来将 TypeScript 转换为 WebAssembly。
4.TeaVM 是一个将 Java 转译到 JavaScript 的工具,现在也可以生成 WebAssembly 了。
5.Go 1.11 为 WebAssembly 增加了一个试验性项目,其编译后的 WebAssembly 模块包含一个垃圾回收器。
6.Pyodide 是 Python 的一个项目,其中包含了 Python 科学栈的核心包:Numpy、Pandas 和 matplotlib。
7.Blazor 是微软的实验性项目,用于将 C# 引入 WebAssembly。

更多列表关注 github: WebAssembly 支持列表。

用途

目前大多数浏览器厂商都已经支持 WebAssembly,包括 Chrome、Edge、Firefox 和 Safari。移动端 Web 浏览器也同样支持。Node.js 也从版本 8 开始支持。WebAssembly 不是 JavaScript 的替代品,而是它的一个补充,有些情况下 WebAssembly 是更好的选择,有些情况下使用 JavaScript 会是一个更优的方案。与 JavaScript 在同一个 VM 运行可让两种技术相辅相成。

WebAssembly 为非 JavaScript 的开发者提供了一个新的道路,帮助在 Web 中使用自己编写的代码。也让不了解 C 或 C++ 等语言的 web 开发者可与访问更新、更快的库。也可用来优化某些库的执行速度。

使用案例

Figma - 基于浏览器的多人实时协作 UI 设计工具

Google Earth - 17 年开始支持在 FireFox 打开,主要依赖 webAssembly。之前使用 Native Client 导致只能在 chrome 中运行

Magnum - 跨平台的 OpenGL 图形引擎

Egret Engine - 一款 HTML5 游戏引擎

Web-DSP - 使用浏览器就能即时制作多媒体影音特效


最新版本:2.0
于2022年6月1日发行。

官方主页:https://webassembly.org/