載入和執行 WebAssembly 程式碼

要在 JavaScript 中使用 WebAssembly,您首先需要在編譯/例項化之前將模組載入到記憶體中。本文提供了有關可用於獲取 WebAssembly 位元組碼的不同機制的參考,以及如何編譯/例項化然後執行它的參考。

有哪些選項?

WebAssembly 尚未與<script type='module'>import語句整合,因此沒有路徑可以讓瀏覽器使用匯入為您獲取模組。

較舊的WebAssembly.compile/WebAssembly.instantiate方法要求您在獲取原始位元組後建立一個包含 WebAssembly 模組二進位制檔案的ArrayBuffer,然後編譯/例項化它。這類似於new Function(string),除了我們用位元組陣列緩衝區(WebAssembly 原始碼)替換字元字串(JavaScript 原始碼)。

較新的WebAssembly.compileStreaming/WebAssembly.instantiateStreaming方法效率更高——它們直接對來自網路的原始位元組流執行操作,無需ArrayBuffer步驟。

那麼我們如何將這些位元組放入陣列緩衝區並進行編譯呢?以下部分將進行說明。

使用 Fetch

Fetch是一個方便的現代 API,用於獲取網路資源。

獲取 Wasm 模組最快、最有效的方法是使用較新的WebAssembly.instantiateStreaming()方法,該方法可以將fetch()呼叫作為其第一個引數,並且將一步完成獲取、編譯和例項化模組的操作,在模組從伺服器流式傳輸時訪問原始位元組碼

js
WebAssembly.instantiateStreaming(fetch("simple.wasm"), importObject).then(
  (results) => {
    // Do something with the results!
  },
);

如果我們使用較舊的WebAssembly.instantiate()方法(它不適用於直接流),我們需要額外的一步將獲取的位元組碼轉換為ArrayBuffer,如下所示

js
fetch("module.wasm")
  .then((response) => response.arrayBuffer())
  .then((bytes) => WebAssembly.instantiate(bytes, importObject))
  .then((results) => {
    // Do something with the results!
  });

關於 instantiate() 過載

WebAssembly.instantiate()函式有兩種過載形式——上面顯示的形式將要編譯的位元組碼作為引數,並返回一個 Promise,該 Promise 解析為一個包含編譯後的模組物件及其例項化例項的物件。該物件如下所示

js
{
  module: Module, // The newly compiled WebAssembly.Module object,
  instance: Instance, // A new WebAssembly.Instance of the module object
}

注意:通常我們只關心例項,但如果我們想要快取它、透過postMessage()與其他工作執行緒或視窗共享它,或者建立更多例項,則擁有模組很有用。

注意:第二種過載形式將WebAssembly.Module物件作為引數,並直接返回一個包含例項物件作為結果的 Promise。請參閱第二個過載示例

執行您的 WebAssembly 程式碼

一旦您在 JavaScript 中獲得了 WebAssembly 例項,您就可以開始使用透過WebAssembly.Instance.exports屬性匯出的其功能。您的程式碼可能如下所示

js
WebAssembly.instantiateStreaming(fetch("myModule.wasm"), importObject).then(
  (obj) => {
    // Call an exported function:
    obj.instance.exports.exported_func();

    // or access the buffer contents of an exported memory:
    const dv = new DataView(obj.instance.exports.memory.buffer);

    // or access the elements of an exported table:
    const table = obj.instance.exports.table;
    console.log(table.get(0)());
  },
);

注意:有關 WebAssembly 模組匯出工作原理的更多資訊,請閱讀使用 WebAssembly JavaScript API瞭解 WebAssembly 文字格式

使用 XMLHttpRequest

XMLHttpRequest比 Fetch 略舊,但仍然可以愉快地用於獲取型別化陣列。同樣,假設我們的模組稱為simple.wasm

  1. 建立一個新的XMLHttpRequest()例項,並使用其open()方法開啟請求,將請求方法設定為GET,並宣告我們要獲取的檔案的路徑。
  2. 這部分的關鍵是使用responseType屬性將響應型別設定為'arraybuffer'
  3. 接下來,使用XMLHttpRequest.send()傳送請求。
  4. 然後,我們使用load事件處理程式在響應完成下載時呼叫一個函式——在這個函式中,我們從response屬性獲取陣列緩衝區,然後將其饋送到我們的WebAssembly.instantiate()方法中,就像我們使用 Fetch 時一樣。

最終程式碼如下所示

js
const request = new XMLHttpRequest();
request.open("GET", "simple.wasm");
request.responseType = "arraybuffer";
request.send();

request.onload = () => {
  const bytes = request.response;
  WebAssembly.instantiate(bytes, importObject).then((results) => {
    results.instance.exports.exported_func();
  });
};

注意:您可以在xhr-wasm.html中看到此示例。