WebAssembly 介紹
出現 WebAssembly 的契機
JS 語言存在的缺陷
- JS只包含64位浮點數(double雙精度浮點數),遵循IEEE754標準,這會導致運算不準確的問題(如:0.1 + 0.2),當然現今的解決方案也很多,如:mathjs、TC39 BigInt、將結果通過toPrecision + parseFloat處理等;
- JS的弱類型可能導致混亂與Bug,現今可以通過TS解決;
- JS不能像編譯語言一樣高效;
- 在之前,若要進行web開發必須使用JS,雖然業界有各式各樣的Transpiler,但歸根結底還是將其它源碼編譯成了JS,受限於JS的特性
谷歌與火狐對支持編譯語言的不同實現
谷歌Native Client(NaCl)(已廢棄)
NaCl
使用SFI技術,使瀏覽器可以安全地運行原生代碼,並可以使用CPU的全部功能,PNaCl為NaCl
增加了可移植性
PNaCl
與NaCl
的編譯與運行

PNaCl
通過Pepper與瀏覽器JS之間通信

NaCl的廢棄
除Chrome以外,其它瀏覽器廠商認為使用NaCl(PNaCl),應用程序將運行在一個黑盒中,對其安全性產生質疑。最終2017年5月,NaCl被廢棄,取而代之的是WebAssembly
火狐asm.js
asm.js
為開發人員提供了一種將c/c++源碼轉換為JS的方法(JS的嚴格子集)。例如使用Emscripten,c/c++代碼可以編譯為asm.js,js引擎識別到asm.js將會將其直接轉換為彙編,利用WebGL通過GPU執行asm.js,極大的提升運行速度。其次asm.js
模塊也可以與JS模塊交互
JS的AOT編譯

asm.js
是WebAssembly最小可行產品(MVP)的基礎
asm.js
的缺點:asm.js是一個文本文件,在進行任何編譯前必須通過網絡傳輸,而Webassembly則採用二進制格式,其體積更小,因此傳輸效率更高
WebAssembly誕生
2015年4月,W3C成立WebAssembly工作組,用於監督與規範WebAssembly提案,倡導瀏覽器廠商使用一致性的規範。
WebAssembly的目標
- 規範瀏覽器廠商協作;
- JS使用WebAssembly代碼像導入一個模塊一樣簡單;
- 不取代JS引擎,僅僅是為其添加一個新特性。
WebAssembly實質
簡介
WebAssembly是一個底層虛擬機,.wasm 是基於堆棧虛擬機的二進制指令格式,WebAssembly的設計目標是編譯高級語言(c/c++/Rust等),提供可移植的結果,支持部署到web端及服務端
核心
堆棧虛擬機
堆棧虛擬機
由兩個元素組成:棧(數據結構)、指令,棧存在兩個操作:push、pop,遵循後進先出
,棧還包括指向棧頂項的指針。指令表示要對棧裡面項執行的操作。
示例,下面ADD指令會彈出棧頂兩項,經過求和指令後,將結果推回棧:

WebAssembly編譯
WebAssembly的MVP專注於C/C++,所以編譯主要是通過Clang/LLVM/Emscripten等實現
WebAssembly語義階段
當瀏覽器獲取到.wasm
文件(二進制),JS引擎將使用解碼棧解碼,將wasm文件轉換為AST,執行類型檢查,並將其解釋為執行函數。示例圖:

說明
階段 | 說明 |
---|---|
Decoding | 解碼,將二進制格式轉換為模塊 |
Validation | 驗證,對解碼後的模塊進行驗證(如類型檢查),以確保模塊良好且安全 |
Phase-1: Instantiation | 實例化第一階段,通過Globals、Memories、Tables,生成初始化模塊實例,並調用start()函數 |
Phase-2: Invocation | 實例化第二階段,導出函數:從模塊實例調用 |
應用場景
- 圖像/視頻編輯
- 遊戲
- 音樂流媒體、緩存
- 圖像識別
- 直播視頻
- VR & AR
雖然以上應用也可以使用JS,但使用WebAssembly可以極大的提升其性能,並且通過二進制文件可以極大的減少js編譯後文件(例如React的bundle)大小,在頁面上加載實例化wasm模塊可以加快代碼執行(WebAssembly自身線程)
限制
- 暫時不支持GC,C/C++的內存管理構建在語言中,而JAVA使用GC(程序不再使用的對象佔用內存將被自動回收);
- 不能直接訪問DOM,可以通過JS、Emscripten完成操作
- 對老版本瀏覽器不兼容,當前支持Webassembly的瀏覽器
Emscripten
Emscripten
是一個LLVM-to-JS
的編譯器,其接受諸如Clang編譯產出的LLVM位碼輸出,並將其轉換為JS。Emscripten
是一種構建、編譯、運行asm.js的技術組合。
生成wasm模塊,可以使用Emscripten SDK
管理器:
