WebAssembly:未来的字节代码
#javascript #网络开发人员 #webassembly

自Netscape启动JavaScript以来,有些开发人员喜欢它,而其他开发人员则不喜欢。

无论您站在哪一方,我都可以同意如果浏览器支持更多编程语言

这是WebAssembly的承诺:提供任何编程语言可以编译为。

过去的尝试

在Web的早期,尝试使用Java Applet和Microsoft ActiveX进行扩展。但是两者都受到安全问题的困扰,并最终下降了。问题是他们像本机代码一样执行 - 没有访问控件 - 它变成了巨大的攻击表面。

后来,Macromedia Flash和Silverlight取得了一些成功,但最终遇到了同样的悲剧命运。他们俩都缺乏开放标准,这使浏览器和OS供应商很难支持。

什么是WebAssembly?

WebAssembly (aka wasm)是open standard字节代码格式,可在所有浏览器中起作用。这是一种低级二进制格式和执行引擎,从概念上类似于Oracle的JVM或Microsoft的CLR。

它是从头设计的,以托管和安全。它无法访问机器的内存或硬盘驱动器。只有主机可以决定要暴露的API。

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

尽管它最初是为了瞄准浏览器而设计的,但也可以在浏览器之外运行。

它可以在服务器,云,物联网/硬件设备上运行,也可以使用插件系统。

写作

有几种创建.wasm文件的方法:

  • 用手写它。 (不建议)
  • Wasm Text Format
  • 使用更高级别的语言,例如汇编,Rust,Ruby等。然后进行编译。

我将向您展示一些示例:

什么是什么?

WASM规范概述了一种基于文本的格式,用于定义称为WAT(WASM文本格式)的WASM模块。它使用类似于lisp或clojure的S-主张。

这是一个基本模块的样子:

; 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 tools的一部分来将.wat文件编译为.wasm

# 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的高级语言。就像WebAssembly的打字稿一样。

例如,上一节的add()函数可以重新编写为assemblyscript:

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

如您所见,它更可读。

要编译它,使用asc

pnpm install -D assemblyscript
pnpm run asc add.ts --outFile=math.wasm

比较格式

要将汇编与WAT进行比较,我构建了一个方便的工具:

https://assemblyscript-play.vercel.app

您也可以使用Cli wasm2wat比较格式:

# outputs .wat format
wasm2wat math.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

WebAssemblies也可以在服务器上执行。 API实际上与浏览器相同。

唯一的区别是,可以使用fs.readFile()
从磁盘上读取它,而不是使用URL从服务器获取.wasm

import fs from 'fs'

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

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

然后,像我们在浏览器中所做的那样,调用导出的功能之一:

const result = module.instance.exports.add(1, 2)

也可以从许多其他语言中执行此操作。例如rustrubypython或来自CLI

在云中使用WebAssembly

WASM的另一个大用例是云。

它比JavaScript云功能具有一些优势:

  1. 没有冷启动:主机只需要加载.wasm文件而不是完整的应用程序。典型的JS应用程序有许多要加载的文件,这需要很长时间。
  2. 更快地部署:所有被上传的都是简单的二进制文件。
  3. 多面体托管:编译为WASM的所有语言都可以部署到云中,而无需任何特殊的运行时。
  4. 快照:可以快照执行。例如,可以在初始化过程中进行昂贵工作的应用程序可以快照。然后将来的请求可以从快照开始,消除了昂贵的启动时间。

云中WASM的一个很好的例子是Fermyon。就像aws lambda,但对于WebAssembly。

要使用Fermyon,请安装他们的Cli spin

然后创建一个新项目:

# 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-Instrest World设计的新型编程语言。