匯出的 WebAssembly 函式

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

匯出的… 什麼?

匯出的 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 函式——這正是我們一直在討論的。

值得注意的是,它們是真正的 JavaScript 函式,同時也是 WebAssembly 函式的包裝器。如果您在 支援 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 位整數。