WebAssembly:未來的字節編碼技術

本文作者是 360 奇舞團的前端工程師

本文爲翻譯,原文略做修改以符合中文語境 原文標題:WebAssembly: byte-code of the future 原文作者:Joshua Nussbaum 原文地址:https://dev.to/joshnuss/webassembly-byte-code-of-the-future-402p

自從 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文件有多種方式:

我們通過以下幾個例子來看下:

什麼是 WAT

WAT(Wasm Text Format)是 WebAssembly 規範提供的一種用於定義 WebAssembly 模塊的文本格式;它使用 S 表達式(S-expressions)的語法,類似於 Lisp 或 Clojure。

例如,以下是一個簡單的 WAT 示例,表示一個將兩個數字相加的 WebAssembly 函數:

; 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 文件

# outputs example.wasm
> wat2wasm example.wat

編譯產出 example.wasm 可以在任何主機執行,使用 wasmtime 命令行工具來執行

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

AssemblyScript

還有一種稱爲 AssemblyScript[4] 的高級語言;它就像是 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

您還可以使用 CLI 工具 wasm2wat 來比較這兩種格式:

# outputs .wat format
wasm2wat math.wasm

運行時執行

就像編譯 wasm 的方式有很多種一樣,執行它的方法也有很多種。

在瀏覽器中使用 WebAssembly

要在瀏覽器中使用 WebAssembly API,首先加載 WebAssembly 模塊:

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

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

然後,調用導出的add的函數:

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

還可以向模塊傳遞其他方法,例如可以共享 console.log 方法:

// 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() 從磁盤上讀取它:

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  函數:

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]   開放標準    https://www.w3.org/groups/wg/wasm[2]   Wasm 文本格式  https://webassembly.github.io/spec/core/text/index.html[3]  WebAssembly Toolkit CLI 工具 https://github.com/WebAssembly/wabt[4]  AssemblyScript https://www.assemblyscript.org/[5]  rust https://docs.rs/wasmer/latest/wasmer[8]  ruby https://github.com/wasmerio/wasmer-ruby[7]  python https://github.com/wasmerio/wasmer-python[8]  CLI https://wasmtime.dev/

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/G5xIkF1OoV8vQ9q2G7wSqQ