本文從為什麼需要WebAssembly、WebAssembly的工作原理、哪些語言可用來創建WebAssembly模塊、WebAssembly可以用在哪裡 以及 怎麼使用 幾方面簡要介紹了webAssembly。如果之前沒有瞭解過webAssembly,可以做一些簡要的瞭解。 ...
1 WebAssembly是什麼?
一種運行在現代網路瀏覽器中的新型代碼,並且提供新的性能特性和效果
W3C WebAssembly Community Group開發的一項網路標準,對於瀏覽器而言,WebAssembly 提供了一條途徑,讓各種語言編寫的代碼以接近原生的速度在 Web 中運行。在這種情況下,以前無法以此方式運行的客戶端軟體等都將可以運行在 Web 中。
WebAssembly 設計之初就決定和 JavaScript 一起協同運行——通過JavaScript 中的 WebAssembly API,可以把 WebAssembly 模塊載入到一個 JavaScript 應用中並且在兩者之間互相調用。這樣可以在同一個應用中使用 WebAssembly 的高性能及 JavaScript 的高靈活性。
2 為什麼需要WebAssembly?
眾所周知JavaScript是解釋型語言,相比於編譯型語言需要在運行時轉換,所以解釋型語言的執行速度要慢於編譯型語言。
編譯型語言和解釋型語言代碼執行的具體流程如下:
因為解釋型語言每次執行都需要把源碼轉換一次才能執行,而轉換過程非常耗費時間和性能,也就導致在JavaScript背景下,web無法執行一些高性能應用,如圖片剪輯、視頻剪輯、3D游戲等。
根據MDN的定義,WebAssembly是一種運行在現代網路瀏覽器中的新型代碼,並且提供新的性能特性和效果。可以在現代的網路瀏覽器中運行 - 它是一種低級的類彙編語言,具有緊湊的二進位格式,可以接近原生的性能運行,併為諸如C / C ++等語言提供一個編譯目標,以便它們可以在Web上運行。它也被設計為可以與JavaScript共存,允許兩者一起工作。
3 WebAssembly的工作原理
WebAssembly不被解釋,而是由開發者提前編譯為WebAssembly二進位格式,如下圖所示。由於變數類型都是預知的,因此瀏覽器載入WebAssembly文件時,JavaScript引擎無須監測代碼。它可以簡單地將這段代碼的二進位格式編譯為機器碼。
如果將每種編程語言都直接編譯為機器碼的各個版本,那麼效率會很低。編譯器中稱為前端的部分會將所編寫的代碼編譯為一種中間表示(intermediate representation,IR)。創建好IR代碼後,編譯器的後端部分會接收IR代碼,對其進行優化,然後將其轉換為所需要的機器碼。
如果將每種編程語言都直接編譯為機器碼的各個版本,那麼效率會很低。編譯器中稱為前端的部分會將所編寫的代碼編譯為一種中間表示(intermediate representation,IR)。創建好IR代碼後,編譯器的後端部分會接收IR代碼,對其進行優化,然後將其轉換為所需要的機器碼。
由於瀏覽器可以在若幹不同的處理器(比如桌面電腦、智能手機和平板設備)上運行,因此為每個可能的處理器發佈一個WebAssembly代碼的編譯後版本會非常繁複。替代方法即取得IR代碼,並通過一個專門的編譯器來運行,這個編譯器將IR代碼轉換為一種專用位元組碼並放入尾碼為.wasm的文件中。此時wasm文件中的位元組碼還不是機器碼,它只是支持WebAssembly的瀏覽器能夠理解的一組虛擬指令。當載入到支持WebAssembly的瀏覽器中時,瀏覽器會驗證這個文件的合法性,然後這些位元組碼會繼續編譯為瀏覽器所運行的設備上的機器碼。如下圖
WebAssembly被設計為JavaScript的一個組件,不是它的替代品。雖然有些開發者試圖只用WebAssembly來創建整個網站,但這不是普遍情況。一般情況JavaScript仍然是更好的選擇。
4 WebAssembly模塊內部
模塊中不同段的含義說明:
編譯器負責生成WebAssembly模塊的段,並將它們按照適當順序放置。
所有的段都是可選的,因此可能存在空模塊。
如果指定了已知段,那麼它們只能出現一次並且要按照特定順序出現。
自定義段可以放置在已知段之前、之間或之後,用於指定不適用已知段的數據。
5 哪些語言可用來創建WebAssembly模塊?
現在WebAssembly的最小可行性版本(Minimum Viable Product,MVP)還沒有垃圾回收(garbage collection,GC),他限制了一些語言的使用。GC作為一種後MVP功能正在開發中,實現之前,有幾種語言正在試驗WebAssembly支持,方式是將自己的VM編譯到WebAssembly,或者在某些情況下將自己的垃圾回收器包含進去。
以下語言正在試驗或已經完成WebAssembly支持:
- C和C++
- Rust正致力於成為WebAssembly的首選編程語言。
- AssemblyScript是一種新編譯器,它用來將TypeScript轉換為WebAssembly。
- TeaVM是一個將Java轉譯到JavaScript的工具,現在也可以生成WebAssembly了。
- Go 1.11為WebAssembly增加了一個試驗性項目,其編譯後的WebAssembly模塊包含一個垃圾回收器。
- Pyodide是Python的一個項目,其中包含了Python科學棧的核心包:Numpy、Pandas和matplotlib。
- Blazor是微軟的實驗性項目,用於將C#引入WebAssembly。
更多列表關註github: WebAssembly支持列表
相關案例:
TeaVM:它可以將 JVM 位元組碼翻譯成 JavaScript 和 WebAssembly
我們有一段時間後端開始做一些前端開發,但是結果有時並不盡如人意,關鍵就在於我們的後端開發人員對前端無論是框架還是語法還是規範,都不是非常瞭解。這是在所難免的,但是因為業務需要又不得不做。
TeaVM就為我們這種情況提供了一種解決方案,我們的後端開發人員依然使用自己熟悉的語言(java)進行開發。功能開發完成後再將_.class或_.jar文件通過TeaVM編譯成wasm或JavaScript供瀏覽器載入調用。
git:https://github.com/konsoletyper/teavm
6 WebAssembly可以用在哪?
目前大多數瀏覽器廠商都已經支持WebAssembly,包括Chrome、Edge、Firefox和Safari。移動端Web瀏覽器也同樣支持。Node.js也從版本8開始支持。
WebAssembly不是JavaScript的替代品,而是它的一個補充,有些情況下WebAssembly是更好的選擇,有些情況下使用JavaScript會是一個更優的方案。與JavaScript在同一個VM運行可讓兩種技術相輔相成。
WebAssembly為非JavaScript的開發者提供了一個新的道路,幫助他們在web中使用自己編寫的代碼。也讓不瞭解C或C++等語言的web開發者可與訪問更新、更快的庫。個人理解WebAssembly也可用來優化某些庫的執行速度。
6.1 一些使用webAssembly的案例
Figma — 基於瀏覽器的多人實時協作 UI 設計工具:https://www.figma.com/
Google Earth https://earth.google.com/ - 17年開始支持在FireFox打開,主要依賴webAssembly。之前使用Native Client導致只能在chrome中運行
Magnum — 跨平臺的 OpenGL 圖形引擎https://github.com/mosra/magnum
Egret Engine - 一款HTML5游戲引擎https://github.com/egret-labs/egret-core/
Web-DSP — 使用瀏覽器就能即時製作多媒體影音特效https://github.com/shamadee/web-dsp
7 WebAssembly怎麼用?
7.1 得到wasm文件手動引入
var importObject = {
imports: {
imported_func: function(arg) {
console.log(arg);
}
}
};
// 輸出 42
fetch('simple.wasm')
.then(res =>
res.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, importObject)
).then(results => {
results.instance.exports.exported_func();
});
7.2 得到編譯好的npm包引入執行
// alert(`Hello, ${name}`)
const js = import("./node_modules/@jdl/hello-wasm/hello_wasm.js");
js.then(js => {
js.greet("WebAssembly");
});
以下為hello_wasm.js文件編譯前源碼
// rust
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
pub fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
本文從為什麼需要WebAssembly、WebAssembly的工作原理、哪些語言可用來創建WebAssembly模塊、WebAssembly可以用在哪裡 以及 怎麼使用 幾方面簡要介紹了webAssembly。如果之前沒有瞭解過webAssembly,可以做一些簡要的瞭解。
參考文獻
《WebAssembly 實戰》 —- C. 傑勒德·加倫特
編譯 Rust 為 WebAssembly - WebAssembly | MDN
作者:京東物流 潘維高
來源:京東雲開發者社區 自猿其說Tech