WASM支持將C/C++/Go/Rust等語言實(shí)現(xiàn)的代碼編譯為瀏覽器可執(zhí)行的機(jī)器碼携龟,從而支持瀏覽器以接近原生應(yīng)用的性能運(yùn)行相關(guān)應(yīng)用峡蟋。在邊緣計(jì)算領(lǐng)域蕊蝗,WASM也在嘗試建立自己的用例蓬戚,為邊緣應(yīng)用提供統(tǒng)一的運(yùn)行環(huán)境子漩。原文:Introduction to WebAssembly (WASM)[1]
WebAssembly于2015年首次發(fā)布幢泼,第一次演示是在Firefox缕棵、Chrome和Edge上執(zhí)行Unity的Angry Bots游戲挥吵。但僅僅過了4年忽匈,它就成為了官方標(biāo)準(zhǔn)丹允,是繼HTML、CSS和JavaScript之后的第四種Web語言折柠。到目前為止扇售,94%的瀏覽器已經(jīng)支持了WebAssembly承冰。它能夠在瀏覽器中實(shí)現(xiàn)接近本機(jī)的執(zhí)行速度食零,使得我們有可能將桌面應(yīng)用(如AutoCAD)甚至電子游戲(如《Doom 3》)移植到Web。
如今幾乎每個(gè)人都在談?wù)揥ebAssembly贰谣。這篇文章將帶你了解什么是WebAssembly以及它是如何工作的百宇。
JavaScript有什么問題恳谎?
什么是WebAssembly?
這是一種類似于C/C++那樣的新的編程語言嗎婚苹?
WebAssembly是如何工作的膊升?
WASM是Web應(yīng)用的未來嗎廓译?
我們將回答所有這些問題评肆,并鼓勵(lì)你開始使用Web匯編(web assembly),它有可能極大的改變我們今天所知道的網(wǎng)站非区!
所以瓜挽,做好準(zhǔn)備,讓我們開始吧征绸!?
JavaScript有什么問題久橙?
JavaScript是由Brenden Eich在1995年為Netscape瀏覽器設(shè)計(jì)的俄占,在那個(gè)年代,它可以為靜態(tài)網(wǎng)頁實(shí)現(xiàn)一些交互缸榄。
JavaScript是解釋型語言,也是動(dòng)態(tài)類型語言。如果變量類型是在運(yùn)行時(shí)決定的砾莱,那么就是動(dòng)態(tài)類型語言。那么動(dòng)態(tài)類型語言的問題是什么呢?
相對(duì)于動(dòng)態(tài)類型語言财松,還有靜態(tài)類型語言甜害,C++就是一種靜態(tài)類型語言眨攘,其變量類型是在定義的時(shí)候就決定了的该肴。
int x = 5 ;
通過一條指令鲤妥,編譯器就能知道變量x的類型和內(nèi)存位置。但是對(duì)于JavaScript中相同的操作衷模,每次執(zhí)行程序時(shí)木蹬,引擎都必須檢查它是整數(shù)還是浮點(diǎn)數(shù),或者任何其他有效的數(shù)據(jù)類型晦譬。所以JavaScript中的每條指令都要經(jīng)過幾次類型檢查和轉(zhuǎn)換惫皱,這會(huì)影響到它的執(zhí)行速度凶硅。
下面是JavaScript在運(yùn)行代碼時(shí)花費(fèi)的時(shí)間??韩脑。
下面是WebAssembly花費(fèi)的時(shí)間进苍。
與JavaScript相比,WebAssembly簡(jiǎn)化了整個(gè)編譯過程。
JavaScript不是為CPU密集型和高性能應(yīng)用程序開發(fā)的。
什么是WebAssembly各吨?
瀏覽器只能運(yùn)行JavaScript忌锯,但如果我們有一個(gè)虛擬微處理器,它可以將任何高級(jí)語言轉(zhuǎn)換成可以在所有主流瀏覽器上運(yùn)行的機(jī)器碼,那會(huì)怎么樣呢?這正是Web匯編(web assembly)所做的事情蛛芥。
下面是一個(gè)用C++編寫并被轉(zhuǎn)為WASM的加法函數(shù)的例子。
VirtualProcessor原理圖,它將C++代碼轉(zhuǎn)換為瀏覽器可理解的二進(jìn)制代碼银酬。
這是一種類似于C/C++那樣的新的編程語言嗎壮韭?
WASM不是一種編程語言??。簡(jiǎn)而言之,它是一種將用一種編程語言編寫的代碼轉(zhuǎn)換為瀏覽器可理解的機(jī)器代碼的技術(shù)。
WASM (WebAssembly的縮寫)被設(shè)計(jì)為其他語言的編譯目標(biāo)济炎,允許服務(wù)器端代碼(如C或C++代碼)被編譯成WASM并在瀏覽器中執(zhí)行。
WebAssembly是如何工作的?
要了解Web匯編(web assembly)蜡豹,我們首先需要了解什么是通用匯編(general assembly)娇唯。
什么是匯編語言和匯編程序想许?
- 每個(gè)處理器都有一個(gè)類似x86或ARM的架構(gòu)漱凝。此外扣典,處理器只能理解機(jī)器碼湿硝。
- 編寫機(jī)器碼是件乏味的事情痢畜,所以我們用匯編語言來編寫凿可。
- 匯編程序?qū)R編語言中的指令轉(zhuǎn)換為處理器能理解的機(jī)器碼敛助。
以下表示了用C語言編寫的應(yīng)用程序是如何在你的電腦上運(yùn)行的评疗。
類似于通用匯編仑荐,在WebAssembly中洒扎,用高級(jí)語言(如C++)編寫的代碼被轉(zhuǎn)換為瀏覽器可理解的機(jī)器碼胡诗。
WebAssembly入門
WebAssembly是一個(gè)具有WASM擴(kuò)展名的文件症虑,可以把它看作一個(gè)可以導(dǎo)入JavaScript程序的模塊。
項(xiàng)目目錄中的交互文件 —
記住颤绕,WASM不能直接與DOM交互,因此我們需要同時(shí)使用JavaScript和WASM。
從上面的討論中,我們了解到,我們可以在瀏覽器中運(yùn)行C杏瞻、C++等語言實(shí)現(xiàn)的應(yīng)用程序,其性能接近原生應(yīng)用浮创。為了實(shí)現(xiàn)這一目標(biāo),我們需要采取以下步驟厕倍。??
1. 用你喜歡的語言編寫應(yīng)用程序。
我們編寫一個(gè)小型C++函數(shù),用來查找Fibonacci數(shù)列的第n個(gè)元素。
// Following is a function that finds nth fibonacci written in C++
int fib(int n)
{
if (n <= 1)
return n;
return fib(n-1) + fib(n-2);
}
2. 創(chuàng)建WASM模塊。
現(xiàn)在匙瘪,我們需要將C++文件轉(zhuǎn)換為瀏覽器能夠理解的預(yù)編譯WASM模塊。
有多種方法可以將高級(jí)語言代碼轉(zhuǎn)換為WASM。但在本教程中,我們將使用Web Assembly Explorer[2]藏研。
步驟1:復(fù)制粘貼C++代碼,然后點(diǎn)擊編譯(compile)。
步驟2:點(diǎn)擊匯編(assemble)嘹承。
步驟3:下載wasm文件。
將下載的文件復(fù)制粘貼到項(xiàng)目目錄叹卷,命名為“math.wasm”。
3. 分發(fā)模塊——通称核可以使用CDN實(shí)現(xiàn)低延遲分發(fā)骤竹,但在這個(gè)演示中,我們只在本地運(yùn)行WASM文件往毡。
創(chuàng)建script.js
蒙揣,暫時(shí)存為空文件。
你的項(xiàng)目目錄應(yīng)該如下所示卖擅。
4. 加載WASM模塊
我們將創(chuàng)建loadWebAssembly()
函數(shù)將給定文件轉(zhuǎn)換為數(shù)組緩沖區(qū)鸣奔。然后墨技,該二進(jìn)制數(shù)組緩沖區(qū)可以被轉(zhuǎn)換為WebAssembly模塊。創(chuàng)建數(shù)組緩沖區(qū)的需求與Web匯編內(nèi)存[3]有關(guān)挎狸。瀏覽器可以讀取該模塊實(shí)例扣汪。
你的script.js
看起來差不多像這樣。
let math;
// Let's create a function called loadWebAssembly that converts given file into binary array buffer.
function loadWebAssembly(fileName) {
return fetch(fileName)
.then(response => response.arrayBuffer())
.then(buffer => WebAssembly.compile(buffer)) // Buffer converted to Web Assembly
.then(module => {return new WebAssembly.Instance(module) }); // Instance of Web assmebly module is returened
};
//We call the function for math.wasm for the given Instance.
loadWebAssembly('math.wasm')
.then(instance => {
});
5. 創(chuàng)建模塊實(shí)例锨匆。
下面是最棘手的部分崭别,我們需要在JS文件中引用C++創(chuàng)建的函數(shù)。我們不能直接引用這些函數(shù)恐锣,而是需要使用在WASM文件中生成的名字茅主,這些名字定義在Web Assembly Explorer的WAT列中。
使用下圖中帶下劃線的函數(shù)名土榴。
在你的WAT文件中诀姚,名字可能不一樣。
在
script.js
中玷禽,第1部分是關(guān)于加載WASM文件赫段。第2部分提供了一些簡(jiǎn)單的javascript函數(shù),用于比較javascript和WebAssembly的性能矢赁。??
//---------------------------PART 1--------------------------------------------------------
// Let's create a function called loadWebAssembly that converts given file into binary array buffer.
function loadWebAssembly(fileName) {
return fetch(fileName)
.then(response => response.arrayBuffer())
.then(buffer => WebAssembly.compile(buffer))
.then(module => {return new WebAssembly.Instance(module) });
};
//We call the function for math.wasm
loadWebAssembly('math.wasm')
.then(instance => {
fibc = instance.exports._Z3fibi;
console.log('Call your functions !');
});
//---------------------------PART 2 -----------------------------------------------
// Function written in Javascript for nth fibonacci
function fibj(n)
{
if (n <= 1)
return n;
return fibj(n-1) + fibj(n-2);
}
//This function gives the time required for C++ function
function perfoc(n){
var startTime = performance.now()
var c=fibc(n)
var endTime = performance.now()
console.log(`Calculating nth Fibonacci with WASM took ${endTime - startTime} milliseconds,nth fibonacci is ${c}`)
}
// This function gives the time required for Javascript function
function perfoj(n){
var startTime = performance.now()
var j=fibj(n)
var endTime = performance.now()
console.log(`Calculating nth Fibonacci with JS took ${endTime - startTime} milliseconds, nth fibonacci is ${j}`)
}
6. 調(diào)用實(shí)例函數(shù)糯笙。
現(xiàn)在可以在本地主機(jī)上加載網(wǎng)站并完成演示!
注意:不能直接運(yùn)行index.html撩银,因?yàn)檫@樣就不會(huì)加載WASM模塊给涕,可以用Visual Studio Code的Live Server擴(kuò)展[4]或者Xampp拉起本地主機(jī)上的項(xiàng)目目錄。
轉(zhuǎn)到控制臺(tái)额获,我們可以調(diào)用以下兩個(gè)函數(shù)够庙。
-
fibj()
→這是用簡(jiǎn)單的Javascript編寫的。 -
fibc()
→這是用C++編寫的咪啡,然后轉(zhuǎn)換為WebAssembly首启。
下面是純JavaScript編寫的函數(shù)(fibj()
)和從WebAssembly導(dǎo)入的函數(shù)(fibc()
)之間的比較撤摸。
fibj()
和fibc()
的執(zhí)行時(shí)間是通過以下函數(shù)度量的:
-
perfoj()
→告訴我們fibj()
所消耗的時(shí)間 -
perfoc()
→告訴我們fibc()
所消耗的時(shí)間
正如我們?cè)谏厦娴腉IF中所看到的毅桃,fibj()
(用JavaScript編寫)所花費(fèi)的時(shí)間比fibc()
(用WebAssembly編寫)要高。
WebAssembly是Web應(yīng)用的未來嗎准夷?
通過web匯編钥飞,我們可以開發(fā)接近原生性能的高性能web應(yīng)用程序,可以執(zhí)行視頻處理衫嵌、3D渲染读宙、多媒體游戲、加密計(jì)算和AR/VR實(shí)時(shí)應(yīng)用程序等任務(wù)楔绞。
因此结闸,基本上唇兑,任何需要大量編碼和性能優(yōu)化的應(yīng)用程序都是WebAssembly的完美用例。
你可以自己嘗試任何可能性桦锄!????
本文所有代碼在這里:https://github.com/Chandrashekhar-D/Introduction-to-WASM/
參考內(nèi)容:
[1]:官方網(wǎng)站扎附。什么是WebAssembly?https://webassembly.org/
[2]:Mozilla结耀。加載和運(yùn)行WebAssembly留夜。https://developer.mozilla.org/en-US/docs/WebAssembly/Loading_and_running
[3]:Lin Clark: 用動(dòng)畫介紹WebAssembly。https://youtu.be/HktWin_LPf4
[4]:Guy Royse: WebAssembly簡(jiǎn)介 https://youtu.be/3sU557ZKjUs
[5]:Priyesh Patel: JavaScript到底是如何工作的图甜?https://blog.bitsrc.io/how-does-javascript-really-work-part-1-7681dd54a36d
References:
[1] https://medium.com/dscvitpune/introduction-to-webassembly-wasm-54d505d6d569
[2] https://mbebenita.github.io/WasmExplorer/
[3] https://www.oreilly.com/library/view/webassembly-the-definitive/9781492089834/ch04.html
[4] https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer
你好碍粥,我是俞凡,在Motorola做過研發(fā)黑毅,現(xiàn)在在Mavenir做技術(shù)工作嚼摩,對(duì)通信、網(wǎng)絡(luò)博肋、后端架構(gòu)低斋、云原生、DevOps匪凡、CICD、區(qū)塊鏈掘猿、AI等技術(shù)始終保持著濃厚的興趣病游,平時(shí)喜歡閱讀、思考稠通,相信持續(xù)學(xué)習(xí)衬衬、終身成長(zhǎng),歡迎一起交流學(xué)習(xí)改橘。
微信公眾號(hào):DeepNoMind