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`
)
)
该文件可以使用WebAssembly Toolkit CLI 工具的一部分.wat进行编译:.wasmwat2wasm
# outputs example.wasm
> wat2wasm example.wat
现在.wasm可以从任何主机执行该命令。甚至可以使用命令行执行wasmtime:
# invoke "add" function, and pass args 1,2
> wasmtime example.wasm --invoke add 1 2
3
AssemblyScript
还有一种更高级的语言叫做AssemblyScript,它就像是 WebAssembly 的 TypeScript。
如果我们用 AssemblyScript 重写add()上一节中的函数,它将如下所示:
// in add.ts
export function add(a: u32, b: u32): u32 {
return a + b;
}
如你所见,现在更容易阅读了。
要编译它,请使用 AssemblyScript 的编译器asc:
pnpm install -D assemblyscript
pnpm run asc add.ts --outFile=math.wasm
比较格式
为了比较 AssemblyScript 和 WAT,我编写了一个小工具:
https://assemblyscript-play.vercel.app
您还可以使用 CLIwasm2wat来比较格式:
# outputs .wat format
wasm2wat math.wasm
运行时执行
就像编译 wasm 有很多种方法一样,执行 wasm 也有很多种方法。
在浏览器中使用 WebAssembly
要在浏览器中使用 WebAssembly API,首先需要加载程序集:
// fetch .wasm file
const response = fetch('/path/to/some.wasm')
// instantiate module with streaming
const module = WebAssembly.instantiateStreaming(response)
然后,调用其中一个导出的函数:
const result = module.instance.exports.add(1, 2)
模块中还可以传入一个可选的 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
}
})
在服务器上使用 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)
然后,调用其中一个导出的函数,就像我们在浏览器中所做的那样:
const result = module.instance.exports.add(1, 2)
也可以用其他很多语言实现这一点。例如,Rust、Ruby、Python或命令行界面(CLI)。
在云端使用 WebAssembly
WASM 的另一个重要应用场景是云计算。
它相比 JavaScript 云函数具有一些优势:
- 无需冷启动:主机只需加载一个
.wasm文件,而不是整个应用程序。典型的 JavaScript 应用程序需要加载很多文件,这会花费很长时间。 - 部署速度更快:只需上传一个简单的二进制文件。
- 多语言托管:所有编译成 WASM 的语言都可以部署到云端,而无需任何特殊的运行时环境。
- 快照:执行过程可以被快照。例如,一个在初始化期间执行耗时操作的应用程序可以被快照。然后,后续请求可以从该快照开始,从而消除昂贵的启动时间。
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
然后定义一个处理程序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
}
}
以开发者模式运行:
spin watch
要部署到云端™,请运行spin deploy:
spin deploy
注意一下部署是如何瞬间完成的吗?
陷阱
WASM 仍存在一些不足之处:
- WebAssembly 仍然是一项相对较新的技术,目前仍在积极开发中,但发展迅速。
- 目前尚不支持某些编程语言。
- WASM 没有字符串之类的基本数据类型,也没有标准库。这是有意为之。编程语言理应提供自己的标准库。
- 因为“标准库”需要驻留在你的程序内部
.wasm,所以它会使文件大小变大。
随着时间的推移,大部分问题都会得到解决。
未来
过去几年,WebAssembly取得了长足的进步。
最终,所有语言都将拥有编译目标和运行时环境(如果目前还没有的话)。这将使所有语言都能在浏览器、服务器甚至硬件上运行。
它还可能催生出专为 WebAssembly 优先的世界而设计的新型编程语言。
文章来源:https://dev.to/joshnuss/webassemble-byte-code-of-the-future-402p