如果提及近年來讓人最為興奮的新技術(shù),非WebAssembly 莫屬。作為一種低級的類匯編語言,WebAssembly以緊湊二進(jìn)制的格式存儲,為C/C++, Rust等擁有低級內(nèi)存的模型語言提供了新的編譯目標(biāo)。正因如此,WebAssembly體積更小,可以以接近原生性能的速度運(yùn)行。
WebAssembly 技術(shù)本身具有非常多的優(yōu)點(diǎn),雖始于瀏覽器但已經(jīng)開始不斷地被各個語言及平臺所集成,在實際的工業(yè)化落地中,區(qū)塊鏈、邊緣計算、游戲及圖像視頻等多個領(lǐng)域都依靠 WebAssembly 創(chuàng)造出了讓人稱贊的產(chǎn)品。
既然提到了Web技術(shù),就不得不提另一款在Web項目開發(fā)中大放異彩的腳本語言Javascript。1995 年,Brendan Eich 用了不到 10 天就創(chuàng)建了 Javascript,其最初主要應(yīng)用于表單驗證,而非以速度見長。隨著各類應(yīng)用功能的復(fù)雜化,受限于 JavaScript 語言本身動態(tài)類型和解釋執(zhí)行的設(shè)計,其性能問題逐漸凸現(xiàn)。
2008年,圍繞著瀏覽器性能開展的大戰(zhàn)終于在各大瀏覽器廠商間爆發(fā),在先后經(jīng)歷了即時編譯器(JITs),以及用Node.js和Electron構(gòu)建應(yīng)用程序的時期后,WebAssembly有望成為JS引擎突破下一性能瓶頸的轉(zhuǎn)折點(diǎn)。
為此,這兩者經(jīng)常被用于比較,甚至一度出現(xiàn)WebAssembly 終將替代 Javascript的言論。的確,作為類匯編語言,WebAssembly解決了Javascript最常為人詬病的性能問題,也正是基于此,WebAssembly注定不適合開發(fā)人員手寫代碼,只能為其他語言提供一個編譯目標(biāo)。
因此,這兩種技術(shù)的關(guān)系不是競爭,反而更像是合作共贏。通過 Javascript API,你可以將 WebAssembly 模塊加載到你的頁面中。也就是說,你可以通過 WebAssembly 來充分利用編譯代碼的性能,同時保持 Javascript 的靈活性。
下圖為我們展現(xiàn)了JS引擎運(yùn)行程序和運(yùn)行Wasm的耗時對比:
JS引擎運(yùn)行程序時,需要經(jīng)歷源碼轉(zhuǎn)換(parse)、生成字節(jié)碼(compile + optimize)、編譯器優(yōu)化(re-optimize)、代碼執(zhí)行(execute)和內(nèi)存清理(GC)這五個階段:
大部分情況下,JS在執(zhí)行階段將字節(jié)碼編譯成機(jī)器碼,這一階段十分耗時。(這是由于JS的動態(tài)性所導(dǎo)致,相同的代碼會被不同的類型重新編譯)。而Wasm不需要被解析,也不需要在運(yùn)行時動態(tài)檢測數(shù)據(jù)類型,由于它已經(jīng)是字節(jié)碼了,所以只需要簡單解碼,即可包含所有的類型信息。
正是因為Wasm的大部分優(yōu)化工作已經(jīng)在LLVM的前端部分完成了,所以編譯優(yōu)化的工作很少,這便是其高性能的主要體現(xiàn)。
LLVM(Low-Level-Virtural-Machine), 底層虛擬機(jī)架構(gòu),優(yōu)點(diǎn)包括:
WebAssembly與LLVM結(jié)合,不需要為各個語言額外添加前端編譯工具,中間的IL可以不斷地優(yōu)化,僅需添加一個'后端',就可以讓大部分語言編譯成wasm。這個'后端'不同于之前提到的后端,它不會直接生成機(jī)器碼,它生成的wasm,會由瀏覽器wasm運(yùn)行時負(fù)責(zé)編譯運(yùn)行。
這就是WebAssembly的編譯原理, 既然WebAssembly的核心目標(biāo)是與Javascript等Web技術(shù)兼容, 那么其兼容到底程度如何?下面,我們將通過項目實戰(zhàn)來驗證。
注:具體的代碼和Demo示例將在grapecity的公開課中進(jìn)行演示,歡迎各位同學(xué)點(diǎn)擊文末“了解更多”觀看。
在進(jìn)入項目實戰(zhàn)之前,大家需要理解一個核心概念,即JavaScript為何能完全控制WebAssembly代碼,并執(zhí)行下載和編譯運(yùn)行:
可見,JavaScript API為開發(fā)者提供了創(chuàng)建模塊、內(nèi)存、表格和實例的能力。
通過一個WebAssembly實例,JavaScript能夠調(diào)用該實例暴露的函數(shù),把JavaScript函數(shù)導(dǎo)入到WebAssembly實例中,WebAssembly也能調(diào)用JavaScript函數(shù)。
另外,WebAssembly不能直接讀寫DOM,只能調(diào)用JavaScript,并且只能傳入整形和浮點(diǎn)型的原始數(shù)據(jù)作為參數(shù)。因此,JavaScript能夠完全控制WebAssembly代碼實現(xiàn)下載、編譯、運(yùn)行, JavaScript開發(fā)者也可以把WebAssembly想象成一個生成高性能函數(shù)的JavaScript特性。
wasm(Rust):
wasm_bindgen主要用來生成一些膠水代碼,簡化開發(fā)者在JS和wasm之間的方法調(diào)用。
JS:
VSCode+插件Rust
通過簡單介紹 WebAssembly 的應(yīng)用場景和主要特性,我們能更好地夠理解 WebAssembly 技術(shù)的演變過程。如果您想更詳細(xì)的學(xué)習(xí)相關(guān)內(nèi)容,可以點(diǎn)擊下方“了解更多”觀看視頻進(jìn)行學(xué)習(xí)。