WebAssembly:未来的字节编码技术

本文作者是360奇舞团的前端工程师
本文为翻译,原文略做修改以符合中文语境 原文标题:WebAssembly: byte-code of the future 原文作者:Joshua Nussbaum 原文地址:dev.to/joshnuss/we...

自从Netscape推出JavaScript以来,一直有一些开发者喜欢它,而另一些则不喜欢。

如果浏览器支持更多的编程语言那就太好了,不管你站在哪一边,我想我们都一致同意。

这是 WebAssembly 的承诺:提供任何编程语言都可以编译的通用运行时。

过去的尝试

在网络的早期,人们尝试使用 Java Applet 和 Microsoft ActiveX 进行扩展;但两者都受到安全问题的困扰,最终被放弃;问题是它们在没有访问控制的情况下执行,这成为了一个巨大的挑战。

后来Macromedia Flash和Silverlight取得了一些成功,但最终也遭遇了同样的悲惨命运;它们都缺乏开放标准,这使得浏览器和操作系统供应商很难支持。

什么是 WebAssembly?

WebAssembly (又名 WASM)是一种 开放标准[1] 字节代码格式,适用于所有浏览器。它是一种低级二进制格式和执行引擎,概念上类似于 Oracle 的 JVM 或 Microsoft 的 CLR。

它的设计初衷就是为了托管和安全,它无法访问机器的内存或硬盘。只有主机可以决定公开哪些 API。

WASM 是一种可移植格式,因此可以支持多种编程语言,认为 Rust、Ruby、Python 甚至 JavaScript 都可以编译为 WASM 字节代码。

尽管它最初是针对浏览器而设计的,但它在浏览器之外也能很好地工作。

它可以在服务器上、云端、硬件设备上运行,或者使用插件系统。

编写 WASM

创建.wasm文件有多种方式:

  • 手动编写(不建议,因为WebAssembly的字节码是一种低级别的二进制表示形式,编写起来非常复杂和容易出错)
  • 使用 Wasm 文本格式[2] 编写。
  • 使用更高级的语言,如 AssemblyScript、Rust、Ruby 等,然后编译它。

我们通过以下几个例子来看下:

什么是WAT

WAT(Wasm Text Format)是WebAssembly规范提供的一种用于定义WebAssembly模块的文本格式;它使用S表达式(S-expressions)的语法,类似于Lisp或Clojure。

例如,以下是一个简单的WAT示例,表示一个将两个数字相加的WebAssembly函数:

bash 复制代码
; define a module
(module
  ; define a function called "add"
  ; it takes 2 params:
  ; - $a is a 32-bit integer
  ; - $b is a 32-bit integer
  ; it returns an 32-bit integer
  (fun add (param $a i32) (param $b i32) (result $i32)
    ; load param $a onto the stack
    local.get $a

    ; load param $b onto the stack
    local.get $b

    ; perform 32-bit integer "add" operation
    i32.add

    ; the last value on the stack is returned
    ; which is the result of the `i32.add`
  )
)

使用 wat2wasm WebAssembly Toolkit CLI 工具[3] 编译.wat文件

markdown 复制代码
# outputs example.wasm
> wat2wasm example.wat

编译产出 example.wasm 可以在任何主机执行,使用 wasmtime 命令行工具来执行

shell 复制代码
# invoke "add" function, and pass args 1,2
> wasmtime example.wasm --invoke add 1 2
3

AssemblyScript

还有一种称为 AssemblyScript[4] 的高级语言;它就像是WebAssembly 的 TypeScript。

如果我们用 AssemblyScript 重写上面例子中的add()函数,它将如下所示:

arduino 复制代码
// in add.ts
export function add(a: u32, b: u32): u32 {
  return a + b;
}

这样对比来看,更具有可读性,对前端开发来讲更友好;

然后使用AssemblyScript 的编译器asc 来编译:

ini 复制代码
pnpm install -D assemblyscript
pnpm run asc add.ts --outFile=math.wasm

格式对比

为了比较 AssemblyScript 和 WAT 格式,我创建了一个小工具:

assemblyscript-play.vercel.app

您还可以使用 CLI 工具 wasm2wat 来比较这两种格式:

lua 复制代码
# outputs .wat format
wasm2wat math.wasm

运行时执行

就像编译 wasm 的方式有很多种一样,执行它的方法也有很多种。

在浏览器中使用WebAssembly

要在浏览器中使用WebAssembly API,首先加载WebAssembly模块:

javascript 复制代码
// fetch .wasm file
const response = fetch('/path/to/some.wasm')

// instantiate module with streaming
const module = WebAssembly.instantiateStreaming(response)

然后,调用导出的add的函数:

java 复制代码
const result = module.instance.exports.add(1, 2)

还可以向模块传递其他方法,例如可以共享 console.log 方法:

javascript 复制代码
// fetch .wasm file
const response = fetch('/path/to/some.wasm')

// instantiate module and pass an api
const module = WebAssembly.instantiateStreaming(response, {
  imports: {
    // share console.log
    log: console.log
  }
  
})

在服务器上使用 WebAssembly

WebAssembly也可以在服务器上执行,使用的方法与在浏览器中的几乎相同。

唯一不同的是,不使用URL从服务器获取.wasm文件,而是使用 fs.readFile() 从磁盘上读取它:

javascript 复制代码
import fs from 'fs'

// read .wasm file
const bytes = await fs.promises.readFile('/path/to/some.wasm')

// instantiate the module
const module = WebAssembly.instantiate(bytes)

然后,调用 add 函数:

java 复制代码
const result = module.instance.exports.add(1, 2)

还可以从许多其他编程语言中执行此操作,例如 rust[5] ruby[6]python[7] 或来自 CLI[8]

在云端使用 WebAssembly

WebAssembly在云端也有一些重要的应用场景。

与JavaScript云函数相比,它具备一些明显的优势:

  1. 无冷启动:主机只需加载一个.wasm文件,而不是整个应用程序;典型的JavaScript应用包含许多需要加载的文件,这会耗费较长的时间。
  2. 更快的部署:需要上传的仅仅是一个简单的二进制文件。
  3. 多语言托管:所有可以编译为WebAssembly的编程语言都可以在云中部署,无需特殊的运行时环境。
  4. 快照:执行状态可以进行快照;例如,一个在初始化期间执行大量计算的应用程序可以创建快照。随后的请求可以从快照状态开始,从而避免浪费大量的启动时间。

注意事项

关于WebAssembly,仍然存在一些问题:

  1. WebAssembly仍然相对较新,并且正在积极开发中,尽管它正在不停的迭代中,但仍存在一些尚未完善的方面。
  2. 尚未为某些编程语言提供完整的支持。
  3. WebAssembly没有像字符串或标准库等基本数据类型,这是故意设计的,各编程语言需要自行提供其标准库。
  4. 由于"标准库"需要包含在.wasm文件中,这可能会导致文件变得较大。

我相信,这些大多数问题会随着时间的推移将得到解决。

未来前景

在过去几年中,WebAssembly取得了许多进展。

最终,几乎所有编程语言都将具备编译到WebAssembly的能力,并提供适用于托管WebAssembly的运行时环境(如果尚未提供的话);这将使所有编程语言都能够在浏览器、服务器甚至硬件上运行。

这也可能催生出专为适应WebAssembly主导的编程环境而设计的新型编程语言。

参考资料

1\] 开放标准 *[www.w3.org/groups/wg/w...](https://link.juejin.cn?target=https%3A%2F%2Fwww.w3.org%2Fgroups%2Fwg%2Fwasm "https://www.w3.org/groups/wg/wasm")* \[2\] Wasm 文本格式 *[webassembly.github.io/spec/core/t...](https://link.juejin.cn?target=https%3A%2F%2Fwebassembly.github.io%2Fspec%2Fcore%2Ftext%2Findex.html "https://webassembly.github.io/spec/core/text/index.html")* \[3\] WebAssembly Toolkit CLI 工具 *[github.com/WebAssembly...](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2FWebAssembly%2Fwabt "https://github.com/WebAssembly/wabt")* \[4\] AssemblyScript *[www.assemblyscript.org/](https://link.juejin.cn?target=https%3A%2F%2Fwww.assemblyscript.org%2F "https://www.assemblyscript.org/")* \[5\] rust *[docs.rs/wasmer/late...](https://link.juejin.cn?target=https%3A%2F%2Fdocs.rs%2Fwasmer%2Flatest%2Fwasmer "https://docs.rs/wasmer/latest/wasmer")* \[8\] ruby *[github.com/wasmerio/wa...](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fwasmerio%2Fwasmer-ruby "https://github.com/wasmerio/wasmer-ruby")* \[7\] python *[github.com/wasmerio/wa...](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fwasmerio%2Fwasmer-python "https://github.com/wasmerio/wasmer-python")* \[8\] CLI *[wasmtime.dev/](https://link.juejin.cn?target=https%3A%2F%2Fwasmtime.dev%2F "https://wasmtime.dev/")*

相关推荐
Ten peaches27 分钟前
Selenium-Java版(环境安装)
java·前端·selenium·自动化
心.c39 分钟前
vue3大事件项目
前端·javascript·vue.js
姜 萌@cnblogs1 小时前
【实战】深入浅出 Rust 并发:RwLock 与 Mutex 在 Tauri 项目中的实践
前端·ai·rust·tauri
蓝天白云下遛狗1 小时前
google-Chrome常用插件
前端·chrome
多多*2 小时前
Spring之Bean的初始化 Bean的生命周期 全站式解析
java·开发语言·前端·数据库·后端·spring·servlet
linweidong2 小时前
在企业级应用中,你如何构建一个全面的前端测试策略,包括单元测试、集成测试、端到端测试
前端·selenium·单元测试·集成测试·前端面试·mocha·前端面经
满怀10152 小时前
【HTML 全栈进阶】从语义化到现代 Web 开发实战
前端·html
东锋1.32 小时前
前端动画库 Anime.js 的V4 版本,兼容 Vue、React
前端·javascript·vue.js
满怀10152 小时前
【Flask全栈开发指南】从零构建企业级Web应用
前端·python·flask·后端开发·全栈开发
小杨升级打怪中3 小时前
前端面经-webpack篇--定义、配置、构建流程、 Loader、Tree Shaking、懒加载与预加载、代码分割、 Plugin 机制
前端·webpack·node.js