Wasm 爲 Web 開發帶來無限可能
大家好,我是 ConardLi
,
Google 開發者大會 (Google Developer Summit) 是 Google 面向開發者和科技愛好者展示最新產品和平臺的年度盛會。2021 年,Google 開發者大會以 “Develop as One” 爲主題,攜手開發者與合作伙伴共創機遇,共謀發展!
今年在 Web 方面,有 Devtools
、PWA
、核心網頁指標、CMS
、隱私沙盒等等:
其中隱私沙盒的最新進展我在前幾天的文章裏已經介紹過,沒看過的的小夥伴可以看這裏:
今天,我們來看看另一個我比較感興趣的議題:WebAssembly
。
本次大會上的分享人是來自 Google
的 WebAssembly
開發技術推廣工程師 Ingvar Stepanyan
。
什麼是 WebAssembly
WebAssembly
是一種二進制指令格式,簡稱爲 Wsam
,它可以運行在適用於堆棧的虛擬機上。
WebAssembly
存在的意義就是成爲編程語言的可移植編譯目標,讓在 Web 上部署客戶端和服務端應用成爲可能。
WebAssembly 可以爲我們帶來什麼
可移植性
如果你的網站現在想用一個能力,但是這個能力還沒有被任何的 JavaScript
庫實現,但是在其他編程領域裏已經有了解決方案。
這時,你就可以藉助 WebAssembly
將所需要的庫編譯爲可以在 Web
上運行的二進制格式,在某些情況下甚至你還可以編譯整個應用。一旦編譯到 WebAssembly
,代碼就可以在任何裝有網絡瀏覽器的設備上運行了,例如 PC、手機、平板電腦等等。
安全性
WebAssembly
需要在沙盒中運行,在沙盒中,除了初始化時程序主動提供給它的內容,它無法訪問其他主機的內存和函數。
這意味着, WebAssembly
,在你沒有給它下發命令的情況下,永遠不會損壞你的主機進程內存,也無法隨意訪問文件系統或與其他設備通信。這就讓它與運行在虛擬機和容器中的應用有相同的優勢
高效
與 JavaScript
等人類可讀的語言相比, WebAssembly
的字節碼可以用更少的字節表示相同的指令,並且在 WebAssembly
模塊依然處於下載期間就可以被編譯。
因爲編譯器已經事先完成了優化工作,在 WebAssembly
中可以更輕鬆的獲取到可預測的性能
WebAssembly 的開源應用
Squoosh
Squoosh
是一個超強的圖像壓縮 Web 應用程序,可讓你深入研究各種圖像壓縮器提供的高級選項,例如比較視覺差異和文件大小以及下載優化後的圖片版本。
https://squoosh.app/
它藉助 WebAssembly
納入了非常多的圖片編解碼器,這些編解碼器可能來源於 C、C++、Rust
等等,在瀏覽器的標籤頁舊可以直接執行它們,不需要服務端做任何額外的處理。這讓 Squoosh
可以處理很多舊的圖片格式(例如 JPEG、PNG
),也可以處理很多新的圖片格式(例如 AVIF、JPEG-XL
)。
FFMpeg
FFmpeg
是視頻處理最常用的開源軟件,它功能強大,用途廣泛,大量用於視頻網站和商業軟件(比如 Youtube
和 iTunes
),也是許多音頻和視頻格式的標準編碼 / 解碼實現。
藉助 WebAssembly
的能力,它現在有了一個 Web 版本:FFMPEG.WASM
,讓你可以在瀏覽器裏處理視頻,你可以到下面這個網址上去體驗一下:
https://ffmpegwasm.netlify.app/
MediaPipe
MediaPipe
是一款由 Google
開發並開源的數據流處理機器學習應用開發框架。它是一個基於圖的數據處理管線,用於構建使用了多種形式的數據源,如視頻、音頻、傳感器數據以及任何時間序列數據。
https://google.github.io/mediapipe/
它支持多個平臺,融入了 WebAssembly
和 WebGL
的強大能力,可以通過 JavaScript
在 Web
上提供機器學習模型。
WebAssembly 用法
如果你現在有一個想要移植到 WebAssembly
的庫,該怎麼用呢?
實際上, WebAssembly
的官網 webassembly.org
是一個很好的開始,上面對於各種語言的教程都是比較全的,在這些教程裏你可以學到怎麼去用相應的工具鏈,怎麼向 WebAssembly
構建代碼,以及如何利用到 Web 上,下面我們看幾個最常用的工具鏈。
Emscripten
Emscripten
是一個開源的編譯器,可以將 C/C++
的代碼編譯成高度優化的 JavaScript
並且高效運行在現代瀏覽器上面,它推出的時間甚至比 WebAssembly
還要早。
現在,它可以將相同的 C/C++
代碼編譯到 WebAssembly
,並提供各種各樣的工具和綁定關係幫助你將生成的代碼繼承到 Web 中。
例如,Emscripten
提供 SDL
實現,可以用於在畫布上繪製內容以及播放 Web 中的音頻,來轉換對 WebGL
的調用。
SDL(簡單直接媒體層)是一個跨平臺的開源開發庫,旨在提供對輸入和圖形硬件的低級訪問,用 C 語言編寫,視頻播放軟件、模擬器和許多流行遊戲都使用它。
Embind
不同語言都擁有不同的類型和內存表示法,JavaScript 和 C++
也不例外,當你編譯成 WebAssembly
也是一樣的情況,所以僅僅通過編譯是無法解決這個問題的。
想要使用這些庫中的結果,還需要一些中間層來轉換雙向傳遞的值。
在 Emscripten
中實現這點最簡單的方法,是使用一個叫 Embind 的功能,下面是一個示例:
// quick_example.cpp
#include <emscripten/bind.h>
using namespace emscripten;
float lerp(float a, float b, float t) {
return (1 - t) * a + t * b;
}
EMSCRIPTEN_BINDINGS(my_module) {
function("lerp", &lerp);
}
通過 EMSCRIPTEN_BINDINGS
塊,就可以以 JavaScript
函數形式聲明對外開放的 API
,以及轉換作爲實參傳遞到 C++
函數的值或者從 C++
返回的值。這樣一來,你就可以將現有任何的 C++
庫封裝到一個對 JavaScript
友好的 API 中。
最後你可以同時編譯 API 封裝容器和之前構建的依賴項,並傳遞一個 --bind
參數來啓用 Embind
。
emcc --bind -o quick_example.js quick_example.cpp
如果將其編譯爲 擴展項,它會生成一個 ES6
兼容模塊,然後你就可以從 JavaScript
代碼導入它,異步初始化這個模塊。
import initModule from './mylib.mjs';
const Module = await initModule();
Module.lerp(1,2,3);
然後你就可以使用之前從 EMSCRIPTEN_BINDINGS
塊聲明的所有 API。
wasm-bindgen
如果你熟悉 Rust
,就知道它在 WebAssembly
領域的貢獻是非常大的。
Rust
提供了 wasm-bindgen
這個工具來支持爲任何 Web API
生成綁定關係,以及將你自己的 Rust
函數導出爲 JavaScript
。
感興趣你可以看一下下面這個在線教程:https://rustwasm.github.io/
。
教程中有將 Rust
函數導出爲 JavaScript
的詳細指引,以及一些示例,和 Embind
一樣,它也負責在語言之間的雙向類型轉換,參考下面這段代碼:
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
當你在一個 extern
塊上應用 wasm_bindgen
屬性時,就可以導入指定的 API
,當你在自己的類型和函數上應用 wasm_bindgen
屬性時,系統會導出相應的類型和函數。
在每種情況下,工具鏈都負責在後臺爲庫生成類型轉換, 以及 JavaScript
封裝容器,甚至是 TypeScript
定義,聲明 API 後,就可以編譯庫生成一個 ES6 模塊。
const rust = import('./pkg');
rust
.then(m => m.greet('World!'))
.catch(console.error);
與 Emscripten
的示例類似,也需要異步將其初始化一次,然後就可以作爲常規的 JavaScript
模塊進行調用。
將 JS/TS 編譯成 WebAssembly
那麼,JavaScript、TypeScript
能不能編譯成 WebAssembly
呢?
答案是否定的,因爲 JavaScript
是高度動態的語言,而 WebAssembly
屬於靜態類型語言,不過我們可以藉助 AssemblyScript
來幫助我們模擬實現這一點。
AssemblyScript
是一個 TypeScript
到 WebAssembly
的編譯器,你可以到 https://www.assemblyscript.org/
去了解它的詳細用法。
未來
WebAssembly
現在已經處於穩定階段了,幾年前就被所有主流瀏覽器所支持,但是它仍在不斷髮展,探索新的能力。
在這些探索中,有一些改進了與 JavaScript
和 Web
的集成,有一些縮減了代碼體積、,還有一些進一步提升了性能,想了解更多,可以到下面的網址進行查看:
https://webassembly.org/roadmap/
現代瀏覽器的功能早已不侷限在簡單的頁面呈現,這就是爲什麼
WebAssembly
會誕生的重要原因之一。爲了將沉重的任務性能提升到一個新的水平,在JavaScript
和機器代碼之間搭建了一座橋樑,由此纔有了WebAssembly
。
讓我們期待 WebAssembly
可以在 Web 上帶給我們更多的可能性吧~
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/50zQO11cheyVkrVueqXgsA