作者:Lin Clark
譯者:xlaoyu
英文原文:Creating a WebAssembly module instance with JavaScript
轉載請註明出處,保留原文連結以及作者資訊
這是 WebAssembly 使用系列介紹的第一篇文章:
- 使用JavaScript建立WebAssembly模組例項
- 安全的WebAssembly記憶體操作
- WebAssembly的匯入型別 table 到底是什麼?
WebAssembly 是一種在瀏覽器中執行程式碼的新方法。通過這項新技術,我們可以使用 C 或 C++ 等語言編寫模組然後執行在瀏覽器中執行它們。
儘管當前這些模組無法直接執行,但是隨著瀏覽器對 ES6 模組規範的逐步支援,這將會有所改變。一旦這一天到來,我們將可以像載入 ES 模組那樣去載入 WebAssembly 模組,比如使用<script type="module">
標籤載入。
目前為止,我們需要使用 JavaScript 來啟動 WebAssembly 模組。首先建立一個模組例項,然後通過再呼叫該 WebAssembly 模組例項上的函式。
(原文提供了一個在 React 中使用 WebAssembly 的視訊,因為需要梯子才能觀看,這裡忽略了)
瀏覽器會先下載 JS 檔案,然後在 js 中去載入 .wasm
檔案(包含 WebAssembly 程式碼的二進位制檔案)。
檔案載入回來後,我們呼叫 WebAssembly.instantiate
方法去例項化 WebAssembly 模組得到一個**WebAssembly例項**。
我們來詳細看看 WebAssembly.instantiate方法的使用,
Promise<ResultObject> WebAssembly.instantiate(bufferSource, importObject);
// or
Promise<WebAssembly.Instance> WebAssembly.instantiate(module, importObject);
複製程式碼
第一種情況的返回結果**ResultObject
**物件包含兩個欄位:
module
- WebAssembly 模組物件表示經過編譯的 WebAssembly 模組,可以重複例項化。instance
- WebAssembly 例項包含了 WebAssembly 模組所有的輸出函式。第二種方式的返回值就是這個物件。
bufferSource是我們準備例項化的包含 .wasm 模組二進位制程式碼的 typed array 或 ArrayBuffer
譯者注:新版 WebAssembly 新增了 instantiateStreaming()
方法,可以直接使用流進行例項化,配合 Fetch API
一起使用可以更進一步提升效能。
JS 引擎會把模組程式碼編譯為針對當前瀏覽器執行機器的程式碼。顯而易見的是,我們不希望這個過程在主執行緒中發生,因為主執行緒就像一個全棧開發那樣需要處理 JavaScript 程式碼、DOM 事件和頁面重繪,我們不能讓編譯阻塞了主執行緒的執行,所以 WebAssembly.instantiate
是返回一個 promise。
通過使用 promise 非同步編譯,主執行緒可以繼續執行其餘的工作。編譯工作一旦完成,promise 會通知主執行緒從 promise 結果中獲取例項。
從上面 instantiate
方法的使用用例可以看到,模組原始碼並不是建立例項唯一需要的東西,還有第二個引數 importObject
。我們可以把 WebAssembly 模組看做是一本說明書,例項物件是一個人,此時人需要根據說明書去做某些事情,所以對應的,他們還需要原材料。
我們直接把 WebAssembly 模組看作 ES6 模組,這個模組暴露了很多方法,而這些方法有些需要入參
,而在 WebAssembly 模組中,我們把這些引數放在 importObject
中傳入。 (原文作者在這裡舉了一個在宜家買東西組裝的?,因為過於抽象,譯者替換為使用 ES6 模組來說明)
所以當我們例項化一個模組時,我們把需要傳入模組的內容掛在 importObject
上,這些內容可以是以下四種型別之一:
- values
- function closures
- memory
- tables
Ps:這裡四個單詞不作翻譯了,感覺強行翻譯就類似於要把 JAVA 翻譯成中文一樣,o(╯□╰)o。
Values
普通值,一般來說是全域性變數。目前 WebAssembly 模組只接收整數和浮點數,所以值必須是這兩種型別之一。將來有可能會增加支援更多的型別。
Function closures
閉包函式,這表示能把 JavaScript 函式傳進去,然後在 WebAssembly 呼叫這些函式。
在當前 WebAssembly 版本中這個特性尤其有用,因為當前我們不能在 WebAssembly 程式碼中直接進行 DOM 操作。此特性可能未來會加入,但是現在還沒有支援。
Memory
memory 物件使 WebAssembly 程式碼可以模擬手動記憶體管理。由於這個物件的概念比較容易讓人產生困惑,尤其是沒有接觸過記憶體管理的純前端開發人員,所以將在下一篇文章(第二篇系列文章)中詳細講解。
Table
最後一個型別是與安全相關的,它能使我們去操作一種叫 函式指標
的東西,將在第三篇文章中詳細說明。
一旦 WebAssembly.instantiate
執行完成,我們從已經 resolved 的 promise 中可以獲取到兩樣東西:例項(instance)和編譯完成的模組物件(module)。
編譯模組的好處是可以快速建立同一模組的其他例項。你所做的就是將模組作為 source
引數傳入。模組本身沒有任何狀態(全部附加到例項)。這意味著例項可以共享已編譯的模組程式碼。
你的例項現在已經裝備齊全並準備好了。它有它的指導手冊,它是編譯的程式碼,以及它的所有輸入物件。我們終於可以呼叫它的方法了。??
下篇文章主要解釋 Memory
到底是什麼東西以及怎麼使用。