WebAssembly入門,未來可期

先來幾個名詞

解釋器

一行行地邊解釋邊執行

此處輸入圖片的描述

編譯器

是把源代碼整個編譯成目標代碼,執行時不再需要編譯器,直接在支持目標代碼的平臺上運行。

此處輸入圖片的描述

解釋器的利弊

  • 解釋器啓動和執行的更快。你不需要等待整個編譯過程完成就可以運行你的代碼。從第一行開始翻譯,就可以依次繼續執行了。
    正是因爲這個原因,解釋器看起來更加適合 JavaScript。對於一個 Web 開發人員來講,能夠快速執行代碼並看到結果是非常重要的。
    這就是爲什麼最開始的瀏覽器都是用 JavaScript 解釋器的原因。

  • 可是當你運行同樣的代碼一次以上的時候,解釋器的弊處就顯現出來了。比如你執行一個循環,那解釋器就不得不一次又一次的進行翻譯,這是一種效率低下的表現。

編譯器的利弊

  • 編譯器的問題則恰好相反。
    它需要花一些時間對整個源代碼進行編譯,然後生成目標文件才能在機器上執行。對於有循環的代碼執行的很快,因爲它不需要重複的去翻譯每一次循環。

Just-in-time 及時編譯(簡稱JIT)

爲了解決解釋器的低效問題,後來的瀏覽器把編譯器也引入進來,形成混合模式。

不同的瀏覽器實現這一功能的方式不同,不過其基本思想是一致的。在 JavaScript 引擎中增加一個監視器(也叫分析器)。監視器監控着代碼的運行情況,記錄代碼一共運行了多少次、如何運行的等信息。

起初,監視器監視着所有通過解釋器的代碼。

如果同一行代碼運行了幾次,這個代碼段就被標記成了 “warm”,如果運行了很多次,則被標記成 “hot”。

基線編譯器

如果一段代碼變成了 “warm”,那麼 JIT 就把它送到編譯器去編譯,並且把編譯結果存儲起來。如果監視器監視到了執行同樣的代碼和同樣的變量類型,那麼就直接把這個已編譯的版本 push 出來給瀏覽器。

優化編譯器

如果一個代碼段變得 “very hot”,監視器會把它發送到優化編譯器中。生成一個更快速和高效的代碼版本出來,並且存儲之。
更多工作原理介紹請移步 JIT工作原理

JavaScript性能變化曲線

此處輸入圖片的描述

JIT不侷限於JS?

JIT總結

簡而言之 JIT 是什麼呢?它是使 JavaScript 運行更快的一種手段(JIT,內聯緩存和隱藏類)之一,通過監視代碼的運行狀態,把 hot 代碼(重複執行多次的代碼)進行優化。通過這種方式,可以使 JavaScript 應用的性能提升很多倍。

爲了使執行速度變快,JIT 會增加很多多餘的開銷,這些開銷包括:

  • 優化和去優化開銷
  • 監視器記錄信息對內存的開銷
  • 發生去優化情況時恢復信息的記錄對內存的開銷

各大廠商的方案

  • 微軟的 TypeScript 通過爲 JS 加入靜態類型檢查來改進 JS 鬆散的語法,提升代碼健壯性;
  • 谷歌的 Dart 則是爲瀏覽器引入新的虛擬機去直接運行 Dart 程序以提升性能;
  • 火狐的 asm.js 則是取 JS 的子集,JS 引擎針對 asm.js 做性能優化。

以上嘗試各有優缺點

  • TypeScript 只是解決了 JS 語法鬆散的問題,最後還是需要編譯成 JS 去運行,對性能沒有提升;
  • Dart 只能在 Chrome 預覽版中運行,無主流瀏覽器支持,用 Dart 開發的人不多;
  • asm.js JS語法子集、有很大限制,開發效率低。關於Asm.js的一些基本介紹和它的實現

三大瀏覽器巨頭分別提出了自己的解決方案,互不兼容,這違背了 Web 的宗旨; 是技術的規範統一讓 Web走到了今天,因此形成一套新的規範去解決 JS 所面臨的問題迫在眉睫。
於是 WebAssembly 誕生了


WebAssembly(Google , Microsoft , Mozilla , Apple 等幾家大公司合作發起的)

WebAssembly 是一種新的字節碼格式,主流瀏覽器都已經支持 WebAssembly。 和 JS 需要解釋執行不同的是,WebAssembly 字節碼和底層機器碼很相似可快速裝載運行,因此性能相對於 JS 解釋執行大大提升。 也就是說 WebAssembly 並不是一門編程語言,而是一份字節碼標準,需要用高級編程語言編譯出字節碼放到 WebAssembly 虛擬機中才能運行.

WebAssembly優點

  • 體積小:由於瀏覽器運行時只加載編譯成的字節碼,一樣的邏輯比用字符串描述的 JS 文件體積要小很多;
  • 加載快:由於文件體積小,再加上無需解釋執行,WebAssembly 能更快的加載並實例化,減少運行前的等待時間;

能編譯成 WebAssembly 字節碼的高級語言有:

  • AssemblyScript:語法和 TypeScript 一致,對前端來說學習成本低。
  • c\c++:官方推薦的方式
  • Rust:語法複雜、學習成本高,對前端來說可能會不適應。
  • Kotlin:語法和 Java、JS 相似,語言學習成本低。

WebAssembly是如何工作的

使用高級語言來編寫WebAssembly模塊,將其編譯成.wasm文件。這些.wasm文件並不能直接被瀏覽器識別,所以它們需要一種稱爲JavaScript膠接代碼(glue code,用於連接相互不兼容的組件,詳見:http://whatis.techtarget.com/definition/glue-code)的東西來加載。

此處輸入圖片的描述

1.Emscripten編譯器

C到WebAssembly的編譯器,推薦使用Emscripten(https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html),安裝這個工具費時費力費空間。

有一個在線 C/C++ 轉 wasm 的工具: WasmExplorer

JavaScript膠接代

function loadWebAssembly (path) {
  return fetch(path)                   // 加載文件        
    .then(res => res.arrayBuffer())    // 轉成 ArrayBuffer
    .then(WebAssembly.instantiate)     // 編譯 + 實例化
    .then(mod => mod.instance)         // 提取生成都模塊
}

其實就是 【加載文件】->【轉成 buffer】->【編譯】->【實例化】

DEMO C語言到WebAssembly

此處輸入圖片的描述

math.c

int square (int x) {
  return x * x;
}

loader.js

見上節JavaScript膠接代

兼容性

各大主流瀏覽器都已經支持!
此處輸入圖片的描述

案例

  • 在2017年5月時,白鷺引擎宣佈開始支持 WebAssembly,而利用 WebAssembly,白鷺引擎可以將 HTML 5 代碼編譯爲機器碼運行,讓遊戲運行性能提升 300%。
  • 2017年10月底,谷歌開始支持讓 Google Earth 在 Firefox 上運行,其中的關鍵就是使用了 WebAssembly。
  • TeaVM 是一個 AOT 編譯器(翻譯器),可將 Java 字節碼翻譯成 JavaScript 或 WebAssembly 格式。
  • Blazor — 讓 .NET 代碼也能在瀏覽器運行
    開源 UI 框架 Blazor 可以讓 .NET 代碼在瀏覽器環境中運行,而習慣 ASP.NET Razor 語法的開發者,仍可以繼續沿用習慣的開發模式

WebAssembly也許是JS性能的第二個拐點,未來可期

此處輸入圖片的描述

既然編譯好後的機器碼執行速度很快,爲啥瀏覽器不嘗試直接支持編譯型語言??

  • JavaScript的歷史地位,WebAssembly與其相輔相成.JavaScript巨大的生態系統和友好的語法,WebAssembly接近原生的表現性能。
  • WebAssembly 字節碼非常接近機器碼,可以非常快的被翻譯爲對應架構的機器碼,因此 WebAssembly 運行速度和機器碼接近。
  • 類比Java 字節碼
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章