发布于 2026-01-06 4 阅读
0

WebAssembly:面向未来的字节码

WebAssembly:面向未来的字节码

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

无论你站在哪一边,我想我们都能同意,如果浏览器支持更多编程语言,那将是件好事

这就是 WebAssembly 的优势所在:提供一个任何编程语言都可以编译成的通用运行时环境。

过去的尝试

在互联网发展的早期,人们曾尝试使用 Java Applet 和 Microsoft ActiveX 来实现扩展功能。但两者都饱受安全问题的困扰,最终都被放弃了。问题在于它们在运行时缺乏访问控制,从而形成了巨大的攻击面。

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

什么是 WebAssembly?

WebAssembly(又名WASM)是一种开放标准的字节码格式,可在所有浏览器中运行。它是一种底层二进制格式和执行引擎,在概念上类似于Oracle的JVM或Microsoft的CLR。

它从一开始就被设计成可托管且安全的。它无法访问机器的内存或硬盘。只有主机才能决定公开哪些 API。

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

虽然它最初是为浏览器设计的,但在浏览器之外也能很好地运行。

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

WASM写作

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

  • 请手写。(不推荐)
  • 请使用Wasm 文本格式编写
  • 使用 AssemblyScript、Rust、Ruby 等高级语言,然后编译它。

我举几个例子:

WAT是什么?

WASM规范提供了一种基于文本的WASM模块定义格式,称为WAT(WASM文本格式)。它使用S表达式,类似于Lisp或Clojure。

以下是一个基本模块的示例:

; 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`
  )
)
Enter fullscreen mode Exit fullscreen mode

该文件可以使用WebAssembly Toolkit CLI 工具的一部分.wat进行编译.wasmwat2wasm

# outputs example.wasm
> wat2wasm example.wat
Enter fullscreen mode Exit fullscreen mode

现在.wasm可以从任何主机执行该命令。甚至可以使用命令行执行wasmtime

# invoke "add" function, and pass args 1,2
> wasmtime example.wasm --invoke add 1 2
3
Enter fullscreen mode Exit fullscreen mode

AssemblyScript

还有一种更高级的语言叫做AssemblyScript,它就像是 WebAssembly 的 TypeScript。

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

// in add.ts
export function add(a: u32, b: u32): u32 {
  return a + b;
}
Enter fullscreen mode Exit fullscreen mode

如你所见,现在更容易阅读了。

要编译它,请使用 AssemblyScript 的编译器asc

pnpm install -D assemblyscript
pnpm run asc add.ts --outFile=math.wasm
Enter fullscreen mode Exit fullscreen mode

比较格式

为了比较 AssemblyScript 和 WAT,我编写了一个小工具:

https://assemblyscript-play.vercel.app

您还可以使用 CLIwasm2wat来比较格式:

# outputs .wat format
wasm2wat math.wasm
Enter fullscreen mode Exit fullscreen mode

运行时执行

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

在浏览器中使用 WebAssembly

要在浏览器中使用 WebAssembly API,首先需要加载程序集:

// fetch .wasm file
const response = fetch('/path/to/some.wasm')

// instantiate module with streaming
const module = WebAssembly.instantiateStreaming(response)
Enter fullscreen mode Exit fullscreen mode

然后,调用其中一个导出的函数:

const result = module.instance.exports.add(1, 2)
Enter fullscreen mode Exit fullscreen mode

模块中还可以传入一个可选的 API:

// 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
  }
})
Enter fullscreen mode Exit fullscreen mode

在服务器上使用 WebAssembly

WebAssembly 也可以在服务器端执行。其 API 与浏览器端的 API 几乎完全相同。

唯一的区别在于,.wasm它不是通过 URL 从服务器获取数据,而是可以直接从磁盘读取数据fs.readFile()

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)
Enter fullscreen mode Exit fullscreen mode

然后,调用其中一个导出的函数,就像我们在浏览器中所做的那样:

const result = module.instance.exports.add(1, 2)
Enter fullscreen mode Exit fullscreen mode

也可以用其他很多语言实现这一点。例如,RustRubyPython或命令行界面(CLI)

在云端使用 WebAssembly

WASM 的另一个重要应用场景是云计算。

它相比 JavaScript 云函数具有一些优势:

  1. 无需冷启动:主机只需加载一个.wasm文件,而不是整个应用程序。典型的 JavaScript 应用程序需要加载很多文件,这会花费很长时间。
  2. 部署速度更快:只需上传一个简单的二进制文件。
  3. 多语言托管:所有编译成 WASM 的语言都可以部署到云端,而无需任何特殊的运行时环境。
  4. 快照:执行过程可以被快照。例如,一个在初始化期间执行耗时操作的应用程序可以被快照。然后,后续请求可以从该快照开始,从而消除昂贵的启动时间。

Fermyon是云端 WASM 的一个绝佳示例。它类似于 AWS Lambda,但专为 WebAssembly 而设计。

要使用 Fermyon,请安装其 CLI版本

然后创建一个新项目:

# create a new spin project
# template is "http-js"
# project name is "spin-example"
spin new http-js spin-example
cd spin-example

# install dependencies
npm install
Enter fullscreen mode Exit fullscreen mode

然后定义一个处理程序src/index.js

const encoder = new TextEncoder()

export async function handleRequest(request) {
  return {
    status: 200,
    headers: { "content-type": "text/plain" },
    body: encoder.encode("Hello World").buffer
  }
}
Enter fullscreen mode Exit fullscreen mode

以开发者模式运行:

spin watch
Enter fullscreen mode Exit fullscreen mode

要部署到云端™,请运行spin deploy

spin deploy
Enter fullscreen mode Exit fullscreen mode

注意一下部署是如何瞬间完成的吗?

陷阱

WASM 仍存在一些不足之处:

  • WebAssembly 仍然是一项相对较新的技术,目前仍在积极开发中,但发展迅速。
  • 目前尚不支持某些编程语言。
  • WASM 没有字符串之类的基本数据类型,也没有标准库。这是有意为之。编程语言理应提供自己的标准库。
  • 因为“标准库”需要驻留在你的程序内部.wasm,所以它会使文件大小变大。

随着时间的推移,大部分问题都会得到解决。

未来

过去几年,WebAssembly取得了长足的进步。

最终,所有语言都将拥有编译目标和运行时环境(如果目前还没有的话)。这将使所有语言都能在浏览器、服务器甚至硬件上运行。

它还可能催生出专为 WebAssembly 优先的世界而设计的新型编程语言。

文章来源:https://dev.to/joshnuss/webassemble-byte-code-of-the-future-402p