十分鐘搞懂WebAssembly

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不是為高性能而開發(fā)的

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í)間??韩脑。

Javascript

下面是WebAssembly花費(fèi)的時(shí)間进苍。

WebAssembly

與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不是一種編程語言

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文件。

編譯和匯編之后(步驟1如庭,步驟2)

將下載的文件復(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)該如下所示卖擅。

項(xià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ù)够庙。

  1. fibj()→這是用簡(jiǎn)單的Javascript編寫的。
  2. fibc()→這是用C++編寫的咪啡,然后轉(zhuǎn)換為WebAssembly首启。
兩個(gè)函數(shù),fibj()和fibc()

下面是純JavaScript編寫的函數(shù)(fibj())和從WebAssembly導(dǎo)入的函數(shù)(fibc())之間的比較撤摸。

WebAssembly快得多

fibj()fibc()的執(zhí)行時(shí)間是通過以下函數(shù)度量的:

  1. perfoj()→告訴我們fibj()所消耗的時(shí)間
  2. 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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末滋尉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子飞主,更是在濱河造成了極大的恐慌狮惜,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碌识,死亡現(xiàn)場(chǎng)離奇詭異碾篡,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)筏餐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門开泽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人魁瞪,你說我怎么就攤上這事穆律』莺簦” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵峦耘,是天一觀的道長(zhǎng)剔蹋。 經(jīng)常有香客問我,道長(zhǎng)贡歧,這世上最難降的妖魔是什么滩租? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮利朵,結(jié)果婚禮上律想,老公的妹妹穿的比我還像新娘。我一直安慰自己绍弟,他們只是感情好技即,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著樟遣,像睡著了一般而叼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上豹悬,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天葵陵,我揣著相機(jī)與錄音,去河邊找鬼瞻佛。 笑死脱篙,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的伤柄。 我是一名探鬼主播绊困,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼适刀!你這毒婦竟也來了秤朗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤笔喉,失蹤者是張志新(化名)和其女友劉穎取视,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體然遏,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贫途,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了待侵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丢早。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出怨酝,到底是詐尸還是另有隱情傀缩,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布农猬,位于F島的核電站赡艰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏斤葱。R本人自食惡果不足惜慷垮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望揍堕。 院中可真熱鬧料身,春花似錦、人聲如沸衩茸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽楞慈。三九已至幔烛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間囊蓝,已是汗流浹背饿悬。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留聚霜,地道東北人乡恕。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像俯萎,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子运杭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容