WebAssembly初识

WebAssembly简介

下面是WebAssembly官方文档给的说明:

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.

大致意思就是"WebAssembly是一个基于栈的二进制指令格式,被设计为编程语言可移植的编译目标,支持部署到web客户端和服务端应用",也就是WebAssembly通常被当作其他编程语言的编译目标 上面的介绍比较太宽泛,下面是WebAssembly核心规范给的定义:

WebAssembly (abbreviated Wasm ) is a safe, portable, low-level code format designed for efficient execution and compact representation. Its main goal is to enable high performance applications on the Web, but it does not make any Web-specific assumptions or provide Web-specific features, so it can be employed in other environments as well.

大致意思就是"WebAssembly(简称为Wasm)是一个安全、可移植的低级代码格式,被设计成高效执行和紧凑表示。它的主要目标是在Web开启高性能应用,但是不做任何特定于Web的假设或提供特定Web的特性,因此它可以也可以部署在其他环境" 两个定义其实都说明了WebAssembly的一些特点,第一个是从广义的角度来讲,第二个是从核心规范的角度来讲

发展历程

WebAssembly的初衷是为了提升Web应用的性能,但是在初版发布之后,WebAssembly在开发者社区越来越流行;因此WebAssembly的潜在价值开始向其他领域蔓延,如云原生、AI以及区块链等。以下是一些关键节点:

  1. 2015年,Mozilla发布一种新型的二进制代码格式"WebAssembly"
  2. 2017年,FireFox、Chrome、Edge和Webkit四大浏览器厂商在WebAssembly MVP(最小可用版本)标准的设计达成共识;同年,WebAssembly Working Group(简称WWG)成立,标识着WebAssembly 成为 W3C 标准技术体系的一部分
  3. 2019年12月,宣布 WebAssembly 成为第 4 种 Web 语言;Bytecode Alliance 字节码联盟宣布正式成立
  4. 2022 年, WebAssembly 2.0 草案正式发布,WebAssembly 2.0 草案中加入了很多值得关注的新特性,比如引用类型(Reference Types)、固定宽度的 SIMD(Fixed-width SIMD)、批量内存操作(Bulk Memory Operations)

规范相关

WebAssembly涉及的内容主要由以下几部分组成:

  1. 核心规范:定义了独立于具体嵌入环境的WebAssembly模块语义,可以理解为Wasm的语义规范
  2. 嵌入的接口:由三部分组成:
    1. JavaScript API:定义从JavaScript访问WebAssembly的类和对象,包括用于验证、编译和实例化的方法,以及导入作为操作和代表、导出作为JavaScript对象的类。
    2. Web API:定义可用于特定浏览器的JavaScript API的扩展,如使用请求的Response作为流式编译和实例化的接口
    3. WASI API:定义了模块化的系统接口,用于Web外运行WebAssembly,包括文件系统、网络连接、锁和随机数
  3. 工具:相关工具,如连接方案、调试信息和语言ABI等
  4. 原始设计文档:WebAssembly的设计、目标和高级概述

特性相关的一些文档/链接:

  1. 特性提案被标准化的流程
  2. 特性提案列表(各个阶段的特性)
  3. 结束的提案(已经进入第四阶段)
  4. 不活跃的提案

WebAssembly有什么优势

  1. 快速、高效 :WebAssembly是静态强类型语言 ,利用常见的硬件能力,可以在不同平台上接近原生的速度运行(我理解的接近原生速度运行是使用C/C++代码编写,编译为Wasm后性能接近C/C++,也就是和原始语言的性能接近)
  2. 跨平台、可移植:WebAssembly是一个可移植、体积小,并且与语言和平台无关的二进制格式,开发者可以使用各种自身熟悉的语言开发,生成的wasm作为平台无关的发布形式
  3. 安全:WebAssembly被限制在一个安全的沙箱环境中运行,一方面可以防止恶意代码攻击,另一方面可以保证数据安全
  4. 标准化 :WebAssembly开放标准是由W3C社区组(包括所有主流浏览的代表)和W3C工作组一同制订的
  5. 灵活的开发语言:WebAssembly制定了标准化的中间指令格式,开发可以使用各自熟悉或喜欢的开发语言进行开发,如C/C++、Java/Kotlin、TypeScript和Rust等

以上这些优势其实也是WebAseembly的设计目标,WebAssembly的设计目标详情可以查看WebAssembly核心规范(设计目标) 上面的优势看起来比较官方,不那么直观,用我的理解通俗一点的解释一下:

  1. 使用支持编译为WebAssembly的语言写的代码可以跨平台运行,目前为止大部分主流语言基本都支持编译为WebAssembly,一套代码在Window、PC、Linux、Android、iPhone、物联网终端运行将成为可能
  2. 可以带来更好的性能,如使用Rust编写的代码编译为Wasm后将会有将近Rust的性能,这对于Web应用来说是质的飞跃

现状

支持编译为Wasm语言

主流语言C/C++、Go、Rust、TypeScript(AssemblyScript)、Java、Python、.Net/C#等等,完整的支持列表可见awesome-wasm-langs 目前支持情况最好的几个语言是:

  1. Rust
  2. C/C++
  3. AsssemblyScript
  4. Blazor
  5. Python
  6. Go

以上一些语言的详细信息可以查看【字节跳动】WebAssembly常用开发语言和工具链 针对开发WebAssembly应用程序的常用语言,有机构进行了相关的调查,近两年的调查结果如下: 相关资料The State of WebAssembly 2021 相关资料The State of WebAssembly 2022

编译器

常见的编译器有如下几个:

  1. Emscripten:可以将C/C++代码编译为WebAssembly
  2. wasi-sdk:提供了一个基于LLVM更为纯净将C/C++编译为WebAssembly的编译器,该项目主要仅提供WASI库,其他编译功能主要基于LLVM
  3. TingGo:基于LLVM将Go编译为WebAssembly的轻量编译器,可以在嵌入式场景使用
  4. wasm-pack:将Rust代码编译WebAssembly并打包成npm模块
  5. wasm-bindgen:一个Rust工具,用来将JavaScript能力导入到Rust或将Rust能力到处到JavaScript(这不算一个编译器,但在Rust生态经常和wasm-pack一起使用)
  6. AssemblyScript:将类TypeScript的AssemblyScript代码编译为WebAssembly的编译器
  7. Binaryen:与语言无关的一个通用的WebAssembly优化器
  8. 等等

详细信息可以查看【字节跳动】WebAssembly常用开发语言和工具链

引擎

有关于引擎的详细信息可以查看【字节跳动】WebAssembly 常见引擎简介

wasmtime

仓库地址github.com/bytecodeall... 是Bytecode Alliance(字节码联盟)推出的拳头项目之一,wasmtime对于WebAssembly相关标准支持的完善度非常高。它支持了标准的WASI(WebAssembly System Interface),并紧密跟踪WebAssembly核心特性。目前 Fixed-Width SIMD、Reference Types、Bulk Memory operations成熟提案, 以及Tail-Call、Threads 和 Garbage Collection 等还处于标准实现阶段的提案都已经被支持。 支持的语言:Rust(wasmtime的实现语言)、C/C++、Python、.NET、Go等

wasm3

仓库地址github.com/wasm3/wasm3 wasm3是一款解释执行的轻量级WebAssembly引擎,使用C语言编写。最低可用系统要求:64kb的存储空间和10kb的内存空间。再加上wasm3是纯解释执行,可以在iOS等设备上运行,这一点其他纯编译型引擎无法做到的,使跨平台具有可行性。但是目前wasm3对WebAssembly规范的支持度一般,具体情况如下: 支持的语言:Rust、C/C++、Python3、.NET、Go等

WasmEdge

仓库地址github.com/WasmEdge/Wa... WasmEdge是一款由CNCF(Cloud Native Computing Foundation,云原生计算基金会)托管的WebAssembly引擎,从它的名称也可以看出,WasmEdge主要面向边缘计算、云原生和去中心化应用。和wasmtime一样,WasmEdge也是编译型的wasm引擎,可以按照JIT/AOT两种模式对wasm指令进行编译,并执行。不同之处在于WasmEdge使用LLVM作为编译器后段,利用了LLVM出色的优化编译能力。因此,相比于使用Cranelift的wasmtime,WasmEdge生成的指令更优,执行速度更快。Wasm支持所有标准的WebAssembly特性和大量扩展提案。 支持的语言:Rust、C、Go等

V8

上面几款引擎都是纯粹的WebAssembly引擎,专用于wasm程序的执行,通常在standalone的场景中使用。但是WebAssembly是由四大浏览器厂商联合推出的,最初在Web环境中使用,JavaScript引擎才是wasm最早的执行引擎。 V8 执行 WebAssembly 也是使用编译后执行的方式: 通过自身的 TurboFan 或者 LiftOff 编译后端,进行 JIT 编译后执行。根据一份 2021 年的测试数据,NodeJS 在 Benchmark 上的性能优于 wasmtime,可见 V8 的 性能足以媲美多数专门的wasm引擎。 在标准支持方面,考虑到 V8 一般在 Web 或者 NodeJS 环境中运行 wasm 程序,所以 V8 并不支持 WASI 标准。但是 Chrome & V8 团队作为 wasm 标准制定的主要参与者之一,V8 引擎对 WebAssembly 的 JS API、MVP 以及 Post-MVP 等核心提案都完整支持,并且实验性地支持各类处在探索阶段的提案。因此,如果想要尝试 WebAssembly 的最新提案实现,V8 引擎是一个不错的选择。 支持的语言:C++ WebAssembly官网有一个特性表格,列出了各引擎对特性的支持情况,可以查看你的浏览器支持哪些特性:webassembly.org/roadmap/

调试

目前WebAssembly对以下几种调试方式支持较好:

  1. 使用Chrome的Devtool进行调试,具体如何调试可以查看Chrome开发者工具的文档,支持C/C++、AssemlbyScript等语言编译为WebAssembly调试
  2. 原生调试,这种方式其实不是在调试WebAssembly代码,而是将WebAssembly反编译为原始代码,然后调试原始代码
  3. lld+wasmtime调试:借助 lldb 和 wasmtime 的能力,将 wasm 的调试信息在 JIT 编译时同步转换到 native 格式,可以获得非常接近于原生调试的体验

前端开发建议首选Chrome+Chrome插件的方式,和平时开发使用source面板基本类似,示例如下:

使用场景和未来趋势

使用场景

  1. Web环境:视频解码和GUI控件(爱奇艺的解码)、浏览器平台的虚拟实现(VR)、游戏相关(Doom 3)、数据库、物理引擎等等
  2. 云原生:2022年Docker宣布推出与WASM集成的首个技术预览版、Krustlet(用于将 Kubernetes 管理的工作负载交付给 WASM 运行时的工具,实现的是Kubelet的功能)
  3. 边缘计算
  4. 移动设备、IoT和物联网
  5. 区块链技术

未来趋势

  1. 更好的开发体验
  2. 标准继续推进
  3. 理念、传播和社区

WebAssembly支持的格式

二进制格式

WebAssembly的二进制格式通常使用wasm扩展名,通常使用其它语言编译为WebAssembly的产物就是该格式,是一种紧凑的、机器可度的二进制形式,这也意味着该格式是人为不可读的。 Web浏览器或其他支持WebAssembly运行时环境加载和执行的格式就是该格式,该格式在编译器中呈现的形式可能类似如下:

文本格式

为了能够让人类阅读和编辑 WebAssembly,WebAssembly提供了相应的文本表示。这是一种用来在文本编辑器、浏览器开发者工具等工具中显示的中间形式。相对于二进制格式,文本格式可读性较高,但基本上和汇编语言一个层级,通常使用wat 作为文件后缀(两种格式是可以互转的,在不包含其他语言特性的情况下可以使用wabt工具集的wasm2wat和wat2wasm命令互相转换),wat文件内容类似如下:

运行一个简单的程序

下面介绍一个简单的例子,如何在V8引擎中(浏览器)运行一个wasm模块(这里以AssemblyScript作为WebAssembly的原始开发语言) 在开始之前先介绍一下WebAssembly的一些关键概念,这些概念都一一映射到Web Assembly的JavaScript API中:

  1. 模块:表示一个已经被浏览器编译为可执行机器码的 WebAssembly 二进制代码。一个模块是无状态的,并且像一个二进制大对象(在前端中的就是Blob)一样能够被缓存到IndexedDB中或者在 window 和 worker 之间进行共享。一个模块能够像一个 ES2015 的模块一样声明导入和导出。
  2. 内存:ArrayBuffer,大小可变。本质上是连续的字节数组,WebAssembly 的低级内存存取指令可以对它进行读写操作。
  • 表格:带类型数组,大小可变。表格中的项存储了不能作为原始字节存储在内存里的对象的引用(为了安全和可移植性的原因),如函数。
  • 实例:一个模块及其在运行时使用的所有状态,包括内存、表格和一系列导入值。一个实例就像一个已经被加载到一个拥有一组特定导入全局变量的 ES2015 模块。
  1. 配置AssemblyScript编译环境(省略),编写AssemblyScript代码(以下就是一个简单的add函数)
typescript 复制代码
export function add(a: i32, b: i32): i32 {
  return a + b;
}
  1. 编译AssemblyScript到WebAssembly,AssemblyScript编译成WebAssembly后,除了生成wat、wasm文件外还是生成一个js文件,这个文件包含了一些胶水代码,该例子的js文件内容如下:
typescript 复制代码
async function instantiate(module, imports = {}) {
  // 示例化wasm,返回一个resolve一个WebAssembly实例的Promise
  const { exports } = await WebAssembly.instantiate(module, imports);
  // wasm导出内容
  return exports;
}
export const {
  memory,
  add,
} = await (async url => instantiate(
  await (async () => {
    try {
      // 浏览器环境(这里包含两步:加载wasm、编译wasm为机器码),编译完生成一个模块
      return await globalThis.WebAssembly.compileStreaming(globalThis.fetch(url));
    } catch {
      // 报错使用Node环境兜底
      return globalThis.WebAssembly.compile(
        await (
          await import("node:fs/promises")).readFile(url)
      );
    }
  })(), {
  }
))(new URL("release.wasm", import.meta.url));
  1. 加载wasm、编译wasm、实例化wasm
  2. 在HTML文件中加载该js文件(需要使用ES模块进行加载,因为使用了export),HTML文件代码如下:
html 复制代码
<!DOCTYPE html>
<html lang="en">

  <body>
    <script type="module">
      import { add } from "./build/release.js";

      console.log("wasm add: ", add(34, 26));
    </script>
  </body>

</html>

运行结果如下:

参考资料

  1. WebAssembly官方文档
  2. 【字节跳动】走进WebAssembly世界系列课程
  3. 【MDN WebAssembly教程】WebAssembly Web开发教程
相关推荐
恋猫de小郭18 分钟前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅9 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment9 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端