WebAssembly 對比 JS 及其使用場景

英文: Alexander Zlatkov? ?譯文:Troland

github.com/Troland/how-javascript-works/blob/master/webassembly.md


這是 ?JavaScript 工作原理的第六章程剥。

現(xiàn)在铅匹,我們將會剖析 WebAssembly 的工作原理词疼,而最重要的是它和 JavaScript 在性能方面的比對:加載時(shí)間似芝,執(zhí)行速度扳还,垃圾回收耀鸦,內(nèi)存使用材蹬,平臺 API 訪問赴魁,調(diào)試赡鲜,多線程以及可移植性空厌。

我們構(gòu)建網(wǎng)頁程序的方式正面臨著改革-這只是個(gè)開始而我們對于網(wǎng)絡(luò)應(yīng)用的思考方式正在發(fā)生改變。

首先蝗蛙,認(rèn)識下 WebAssembly 吧

WebAssembly(又稱 wasm) 是一種用于開發(fā)網(wǎng)絡(luò)應(yīng)用的高效蝇庭,底層的字節(jié)碼。

WASM 讓你在其中使用除 JavaScript 的語言以外的語言(比如 C, C++, Rust 及其它)來編寫應(yīng)用程序捡硅,然后編譯成(提早) WebAssembly哮内。

構(gòu)建出來的網(wǎng)絡(luò)應(yīng)用加載和運(yùn)行速度都會非常快壮韭。

加載時(shí)間

為了加載 JavaScript北发,瀏覽器必須加載所有文本格式的 js 文件。

瀏覽器會更加快速地加載 WebAssembly喷屋,因?yàn)?WebAssembly 只會傳輸已經(jīng)編譯好的 wasm 文件琳拨。而且 wasm 是底層的類匯編語言,具有非常緊湊的二進(jìn)制格式屯曹。

執(zhí)行速度

如今 Wasm 運(yùn)行速度只比原生代碼慢 20%狱庇。無論如何,這是一個(gè)令人驚喜的結(jié)果恶耽。它是這樣的一種格式密任,會被編譯進(jìn)沙箱環(huán)境中且在大量的約束條件下運(yùn)行以保證沒有任何安全漏洞或者使之強(qiáng)化。和真正的原生代碼比較偷俭,執(zhí)行速度的下降微乎其微浪讳。另外,未來將會更加快速涌萤。

更讓人高興的是淹遵,它具備很好的瀏覽器兼容特性-所有主流瀏覽器引擎都支持 WebAssembly 且運(yùn)行速度相關(guān)無幾口猜。

為了理解和 JavaScript 對比,WebAssembly 的執(zhí)行速度有多快透揣,你應(yīng)該首先閱讀之前的 JavaScript 引擎工作原理的文章济炎。

讓我們快速瀏覽下 V8 的運(yùn)行機(jī)制:

V8 技術(shù):懶編譯

左邊是 JavaScript 源碼,包含 JavaScript 函數(shù)淌实。首先冻辩,源碼先把字符串轉(zhuǎn)換為記號以便于解析,之后生成一個(gè)語法抽象樹拆祈。

語法抽象樹是你的 JavaScript 程序邏輯的內(nèi)存中圖示恨闪。一旦生成圖示,V8 直接進(jìn)入到機(jī)器碼階段放坏。你基本上是遍歷樹咙咽,生成機(jī)器碼然后獲得編譯后的函數(shù)。這里沒有任何真正的嘗試來加速這一過程淤年。

現(xiàn)在钧敞,讓我們看一下下一階段 V8 管道的工作內(nèi)容:

V8 管道設(shè)計(jì)

現(xiàn)在,我們擁有 TurboFan 麸粮,它是 V8 的優(yōu)化編譯程序之一溉苛。當(dāng) JavaScript 運(yùn)行的時(shí)候,大量的代碼是在 V8 內(nèi)部運(yùn)行的弄诲。TurboFan ?監(jiān)視運(yùn)行得慢的代碼愚战,引起性能瓶頸的地方及熱點(diǎn)(內(nèi)存使用過高的地方)以便優(yōu)化它們。它把以上監(jiān)視得到的代碼推向后端即優(yōu)化過的即時(shí)編譯器齐遵,該編譯器把消耗大量 CPU 資源的函數(shù)轉(zhuǎn)換為性能更優(yōu)的代碼寂玲。

它解決了性能的問題,但是缺點(diǎn)即是分析代碼及辨別哪些代碼需要優(yōu)化的過程也是會消耗 CPU 資源的梗摇。這也即意味著更多的耗電量拓哟,特別是在手機(jī)設(shè)備。

但是伶授,wasm 并不需要以上的全部步驟-它如下所示插入到執(zhí)行過程中:

V8 管道設(shè)計(jì) + WASM

wasm 在編譯階段就已經(jīng)通過了代碼優(yōu)化断序。總之糜烹,解析也不需要了逢倍。你擁有優(yōu)化后的二進(jìn)制代碼可以直接插入到后端(即時(shí)編譯器)并生成機(jī)器碼。編譯器在前端已經(jīng)完成了所有的代碼優(yōu)化工作景图。

由于跳過了編譯過程中的不少步驟,這使得 wasm 的執(zhí)行更加高效碉哑。

內(nèi)存模型

WebAssembly 可信和不可信狀態(tài)

舉個(gè)栗子挚币,一個(gè) C++ 的程序的內(nèi)存被編譯為 WebAssembly亮蒋,它是整段連續(xù)的沒有空洞的內(nèi)存塊。wasam 中有一個(gè)可以用來提升代碼安全性的功能即執(zhí)行堆棧和線性內(nèi)存隔離的概念妆毕。在 C++ 程序中慎玖,你有一塊動態(tài)內(nèi)存區(qū),你從其底部分配獲得內(nèi)存堆棧笛粘,然后從其頂部獲得內(nèi)存來增加內(nèi)存堆棧的大小趁怔。你可以獲得一個(gè)指針然后在堆棧內(nèi)存中遍歷以操作你不應(yīng)該接觸到的變量。

這是大多數(shù)可疑軟件可以利用的漏洞薪前。

WebAssembly 采用了完全不同的內(nèi)存模型润努。執(zhí)行堆棧和 WebAssembly 程序本身是隔離開來的,所以你無法從里面進(jìn)行修改和改變諸如變量值的情形示括。同樣地铺浇,函數(shù)使用整數(shù)偏移而不是指針。函數(shù)指向一個(gè)間接函數(shù)表垛膝。之后鳍侣,這些直接的計(jì)算出的數(shù)字進(jìn)入模塊中的函數(shù)。它就是這樣運(yùn)行的吼拥,這樣你就可以同時(shí)引入多個(gè) wasm 模塊倚聚,偏移所有索引且每個(gè)模塊都運(yùn)行良好。

更多關(guān)于 JavaScript 內(nèi)存模型和管理的文章詳見這里凿可。

內(nèi)存垃圾回收

你已經(jīng)知曉 JavaScript 的內(nèi)存管理是由內(nèi)存垃圾回收器處理的惑折。

WebAssembly 的情況有點(diǎn)不太一樣。它支持手動操作內(nèi)存的語言矿酵。你也可以在你的 wasm 模塊中內(nèi)置內(nèi)存垃圾回收器唬复,但這是一項(xiàng)復(fù)雜的任務(wù)。

目前全肮,WebAssembly 是專門圍繞 C++ 和 RUST 的使用場景設(shè)計(jì)的敞咧。由于 wasm 是非常底層的語言,這意味著只比匯編語言高一級的編程語言會容易被編譯成 WebAssembly辜腺。C 語言可以使用 malloc休建,C++ 可以使用智能指針,Rust 使用完全不同的模式(一個(gè)完全不同的話題)评疗。這些語言沒有使用內(nèi)存垃圾回收器测砂,所以他們不需要所有復(fù)雜運(yùn)行時(shí)的東西來追蹤內(nèi)存。WebAssembly 自然就很適合于這些語言百匆。

另外砌些,這些語言并不能夠 100% 地應(yīng)用于復(fù)雜的 JavaScript 使用場景比如監(jiān)聽 DOM 變化 。用 C++ 來寫整個(gè)的 HTML 程序是毫無意義的因?yàn)?C++ 并不是為此而設(shè)計(jì)的。大多數(shù)情況下存璃,工程師用使用 C++ 或 Rust 來編寫 WebGL 或者高度優(yōu)化的庫(比如大量的數(shù)學(xué)運(yùn)算)仑荐。

然而,將來 WebAssembly 將會支持不帶內(nèi)存垃圾回功能的的語言纵东。

平臺接口訪問


依賴于執(zhí)行 JavaScript 的運(yùn)行時(shí)環(huán)境粘招,可以通過 JavaScript 程序來直接訪問這些平臺所暴露出的指定接口。比如偎球,當(dāng)你在瀏覽器中運(yùn)行 JavaScript洒扎,網(wǎng)絡(luò)應(yīng)用可以調(diào)用一系列的網(wǎng)頁接口來控制瀏覽器/設(shè)備的功能且訪問 DOM,CSSOM衰絮,WebGL袍冷,IndexedDB,Web Audio API 等等岂傲。

然而难裆,WebAssembly 模塊不能夠訪問任何平臺的接口。所有的這一切都得由 JavaScript 來進(jìn)行協(xié)調(diào)镊掖。如果你想在 WebAssembly 模塊內(nèi)訪問一些指定平臺的接口乃戈,你必須得通過 JavaScript 來進(jìn)行調(diào)用。

舉個(gè)栗子亩进,如果你想要使用?console.log症虑,你就得通過JavaScript 而不是 C++ 代碼來進(jìn)行調(diào)用。而這些 JavaScript 調(diào)用會產(chǎn)生一定的性能損失归薛。

情況不會一成不變的谍憔。規(guī)范將會為在未來為 wasm 提供訪問指定平臺的接口,這樣你就可以不用在你的程序中內(nèi)置 JavaScript主籍。

源碼映射

當(dāng)你壓縮了 JavaScript 代碼的時(shí)候习贫,你需要有合適的方法來進(jìn)行調(diào)試。

這時(shí)候源碼映射就派上用場了千元。

大體上苫昌,源碼映射就是把合并/壓縮了的文件映射到未構(gòu)建狀態(tài)的一種方式。當(dāng)你為生產(chǎn)環(huán)境進(jìn)行代碼構(gòu)建的時(shí)候幸海,與壓縮和合并 JavaScript 一起祟身,你會生成源碼映射用來保存原始文件信息。當(dāng)你想在生成的 JavaScript 代碼中查詢特定的行和列的代碼的時(shí)候物独,你可以在源碼映射中進(jìn)行查找以返回代碼的原始位置袜硫。

由于沒有規(guī)范定義源碼映射,所以目前 WebAssembly 并不支持挡篓,但最終會有的(可能快了)婉陷。

當(dāng)你在 C++ 代碼中設(shè)置了斷點(diǎn),你將會看到 C++ 代碼而不是 WebAssembly。至少憨攒,這是 WebAssembly 源碼映射的目標(biāo)吧世杀。

多線程


JavaScript 是單線程的。有很多方法來利用事件循環(huán)和使用在之前的文章中有提到的異步編程肝集。

JavaScript 也使用 Web Workers 但是只有在極其特殊的情況下-大體上,可以把任何可能阻塞 UI 主線程的密集的 CPU 計(jì)算移交給 Web Worker 執(zhí)行以獲得更好的性能蛛壳。但是杏瞻,Web Worker 不能夠訪問 DOM。

目前 WebAssembly 不支持多線程衙荐。但是捞挥,這有可能是接下來 WebAssembly 要實(shí)現(xiàn)的。Wasm 將會接近實(shí)現(xiàn)原生的線程(比如忧吟,C++ 風(fēng)格的線程)砌函。擁有真正的線程將會在瀏覽器中創(chuàng)造出很多新的機(jī)遇。并且當(dāng)然溜族,會增加濫用的可能性讹俊。

可移植性


現(xiàn)在 JavaScript 幾乎可以運(yùn)行于任意的地方,從瀏覽器到服務(wù)端甚至在嵌入式系統(tǒng)中煌抒。

WebAssembly 設(shè)計(jì)旨在安全性和可移植性仍劈。正如 JavaScript 那樣。它將會在任何支持 wasm 的環(huán)境(比如每個(gè)瀏覽器)中運(yùn)行寡壮。

WebAssembly 擁有和早年 Java 使用 Applets 來實(shí)現(xiàn)可移植性的同樣的目標(biāo)贩疙。

WebAssembly 使用場景

WebAssembly 的最初版本主要是為了解決大量計(jì)算密集型的計(jì)算的(比如處理數(shù)學(xué)問題)。最為主流的使用場景即游戲-處理大量的像素况既。

你可以使用你熟悉的 OpenGL 綁定來編寫 C++/Rust 程序这溅,然后編譯成 wasm。之后棒仍,它就可以在瀏覽器中運(yùn)行悲靴。

瀏覽下(在火孤中運(yùn)行)-h(huán)ttp://s3.amazonaws.com/mozilla-games/tmp/2017-02-21-SunTemple/SunTemple.html。這是運(yùn)行于Unreal engine(這是一個(gè)可以用來開發(fā)虛擬現(xiàn)實(shí)的開發(fā)套件)中的降狠。

另一個(gè)合理使用 WebAssembly (高性能)的情況即實(shí)現(xiàn)一些處理計(jì)算密集型的庫对竣。比如,一些圖形操作榜配。

正如之前所提到的否纬,wasm 可以有效減少移動設(shè)備的電力損耗(依賴于引擎),這是由于大多數(shù)的步驟已經(jīng)在編譯階段提前處理完成蛋褥。

未來临燃,你可以直接使用 WASM 二進(jìn)制庫即使你沒有編寫編譯成它的代碼。你可以在 NPM 上面找到一些開始使用這項(xiàng)技術(shù)的項(xiàng)目。

針對操作 DOM 和頻繁使用平臺接口的情況 膜廊,使用 JavaScript 會更加合理乏沸,因?yàn)樗粫a(chǎn)生額外的性能開銷且它原生支持各種接口。

在 SessionStack 我們一直致力于持續(xù)提升 JavaScript 的性能以編寫高質(zhì)量和高效的代碼爪瓜。我們的解決方案必須擁有閃電般的性能因?yàn)槲覀儾荒軌蛴绊懹脩舫绦虻男阅艿旁尽R坏┠惆?SessionStack 整合進(jìn)你的網(wǎng)絡(luò)應(yīng)用或網(wǎng)站的生產(chǎn)環(huán)境,它會開始記錄所有的一切:所有的 DOM 變化铆铆,用戶交互蝶缀,JavaScript 異常,堆棧追蹤薄货,失敗的網(wǎng)絡(luò)請求和調(diào)試數(shù)據(jù)翁都。所有的這一切都是在你的生產(chǎn)環(huán)境中產(chǎn)生且沒有影響到你的產(chǎn)品的任何交互和性能。我們必須極大地優(yōu)化我們的代碼并且盡可能地讓它異步執(zhí)行谅猾。

我們不僅僅有庫柄慰,還有其它功能!當(dāng)你在 SessionStack 中重放用戶會話税娜,我們必須渲染問題產(chǎn)生時(shí)你的用戶的瀏覽器所發(fā)生的一切坐搔,而且我們必須重構(gòu)整個(gè)狀態(tài),允許你在會話時(shí)間線上來回跳轉(zhuǎn)巧涧。為了使之成為可能薯蝎,我們大量地使用異步操作,因?yàn)??JavaScript 中沒有比這更好的替代選擇了谤绳。

有了 WebAssembly占锯,我們就可以把大量的數(shù)據(jù)計(jì)算和渲染的工作移交給更加合適的語言來進(jìn)行處理而把數(shù)據(jù)收集和 DOM 操作交給 JavaScript 進(jìn)行處理。

番外篇

打開 webassembly 官網(wǎng)就可以在頭部醒目地看到顯示它兼容的瀏覽器缩筛。分別是火孤消略,Chrome,Safari瞎抛,IE Edge艺演。點(diǎn)開 learn more 可以查看到這是于 2017/2/28 達(dá)成一致推出瀏覽器預(yù)覽版。現(xiàn)在各項(xiàng)工作開始進(jìn)入實(shí)施階段了桐臊,相信在未來的某個(gè)時(shí)刻就可以在生產(chǎn)環(huán)境使用它了胎撤。官網(wǎng)上面介紹了一個(gè) JavaScript 的子集 asm.js。另外断凶,這里有一個(gè) WebAssembly 和 JavaScript 進(jìn)行性能比對的測試網(wǎng)站伤提。

感興趣的小伙伴,可以關(guān)注公眾號【grain先森】认烁,回復(fù)關(guān)鍵詞 “小程序”肿男,獲取更多資料介汹,更多關(guān)鍵詞玩法期待你的探索~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市舶沛,隨后出現(xiàn)的幾起案子嘹承,更是在濱河造成了極大的恐慌,老刑警劉巖如庭,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叹卷,死亡現(xiàn)場離奇詭異,居然都是意外死亡柱彻,警方通過查閱死者的電腦和手機(jī)豪娜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哟楷,“玉大人,你說我怎么就攤上這事否灾÷羯茫” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵墨技,是天一觀的道長惩阶。 經(jīng)常有香客問我,道長扣汪,這世上最難降的妖魔是什么断楷? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮崭别,結(jié)果婚禮上冬筒,老公的妹妹穿的比我還像新娘。我一直安慰自己茅主,他們只是感情好舞痰,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著诀姚,像睡著了一般响牛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赫段,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天呀打,我揣著相機(jī)與錄音,去河邊找鬼糯笙。 笑死贬丛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的炬丸。 我是一名探鬼主播瘫寝,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼蜒蕾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了焕阿?” 一聲冷哼從身側(cè)響起咪啡,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎暮屡,沒想到半個(gè)月后撤摸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡褒纲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年准夷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片莺掠。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡衫嵌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出彻秆,到底是詐尸還是另有隱情楔绞,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布唇兑,位于F島的核電站酒朵,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏扎附。R本人自食惡果不足惜蔫耽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望留夜。 院中可真熱鬧匙铡,春花似錦、人聲如沸香伴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽即纲。三九已至具帮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間低斋,已是汗流浹背蜂厅。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留膊畴,地道東北人掘猿。 一個(gè)月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像唇跨,于是被迫代替她去往敵國和親稠通。 傳聞我的和親對象是個(gè)殘疾皇子衬衬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

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

  • WebAssembly 系列(一)生動形象地介紹 WebAssemblyWebAssembly 系列(二)Java...
    合肥黑閱讀 7,501評論 0 9
  • 轉(zhuǎn)自:https://fed.renren.com/2017/05/21/webassembly/ Webasse...
    core1988閱讀 2,686評論 0 1
  • Webassembly(WASM)和CSS的Grid布局一樣都是一個(gè)新東西,Chrome從57開始支持改橘。在講was...
    極樂君閱讀 1,728評論 1 4
  • 我恍惚看見有人向我招手 他邁過洶涌的河流穿過巍峨的青山向我緩緩行來 我不知道知道他是誰 我只知道 在桃花盛開的地方...
    ZHAOZIYI閱讀 260評論 0 0