匯出 WebAssembly 函式

匯出 WebAssembly 函式是 WebAssembly 函式在 JavaScript 中的表示方式。本文將更詳細地介紹它們是什麼。

匯出... 什麼?

匯出 WebAssembly 函式本質上只是 JavaScript 包裝器,它們在 JavaScript 中代表 WebAssembly 函式。當您呼叫它們時,後臺會進行一些活動將引數轉換為 Wasm 可以處理的型別(例如,將 JavaScript 數字轉換為 Int32),引數被傳遞到 Wasm 模組內的函式,函式被呼叫,結果被轉換並傳遞迴 JavaScript。

您可以透過兩種方式檢索匯出的 WebAssembly 函式

無論哪種方式,您都將獲得對底層函式的相同型別的包裝器。從 JavaScript 的角度來看,就好像每個 Wasm 函式也是一個 JavaScript 函式一樣——但是它們被匯出的 Wasm 函式物件例項封裝起來,並且只有有限的方法可以訪問它們。

一個示例

讓我們看一個示例來澄清(您可以在 GitHub 上找到它,網址為 table-set.html;也可以檢視 即時執行的示例,並檢視 Wasm 文字表示

js
const otherTable = new WebAssembly.Table({ element: "anyfunc", initial: 2 });

WebAssembly.instantiateStreaming(fetch("table.wasm")).then((obj) => {
  const tbl = obj.instance.exports.tbl;
  console.log(tbl.get(0)()); // 13
  console.log(tbl.get(1)()); // 42
  otherTable.set(0, tbl.get(0));
  otherTable.set(1, tbl.get(1));
  console.log(otherTable.get(0)());
  console.log(otherTable.get(1)());
});

在這裡,我們使用 WebAssembly.Table 建構函式從 JavaScript 建立一個表 (otherTable),然後我們使用 WebAssembly.instantiateStreaming() 方法將 table.wasm 載入到我們的頁面中。

然後,我們獲取從模組匯出的函式,透過 tbl.get() 檢索它引用的函式,並將每個函式呼叫的結果記錄到控制檯。接下來,我們使用 set() 使 otherTable 表包含與 tbl 表相同的函式引用。

為了證明這一點,我們然後從 otherTable 檢索這些引用,並將它們的結果也列印到控制檯,這將給出相同的結果。

它們是真正的函式

在前面的示例中,每個 Table.prototype.get() 呼叫的返回值都是一個匯出的 WebAssembly 函式——這正是我們一直在討論的內容。

值得注意的是,除了作為 WebAssembly 函式的包裝器之外,它們還是真正的 JavaScript 函式。如果您在支援 WebAssembly 的瀏覽器 中載入上述示例,並在您的控制檯中執行以下程式碼行

js
const testFunc = otherTable.get(0);
typeof testFunc;

您將獲得返回的 function 結果。然後,您可以對該函式執行幾乎所有您可以對 JavaScript 中的其他 函式 執行的操作——call()bind() 等等。testFunc.toString() 返回一個有趣的結果

function 0() {
    [native code]
}

這可以讓您更瞭解其包裝器的性質。

關於匯出的 WebAssembly 函式,還有一些其他需要注意的細節

  • 它們的 length 屬性是 Wasm 函式簽名中宣告的引數數量。
  • 它們的 name 屬性是 Wasm 模組中函式索引的 toString() 結果。
  • 如果您嘗試呼叫一個採用或返回 i64 型別值的匯出 Wasm 函式,它目前會丟擲錯誤,因為 JavaScript 目前沒有精確的方法來表示 i64。解決方案是使用 BigInt 值,它們表示任意大小的整數,因此它們可以正確表示 64 位整數。