WebAssembly 系列(六)WebAssembly 的現在與未來

鬍子大哈發表於2017-03-16

作者:Lin Clark

編譯:鬍子大哈

翻譯原文:huziketang.com/blog/posts/…

英文原文:Where is WebAssembly now and what’s next?

轉載請註明出處,保留原文連結以及作者資訊


本文是關於 WebAssembly 系列的第六篇文章(本系列共六篇文章),也同時是本系列的收尾文章。如果你沒有讀先前文章的話,建議先讀這裡。如果對 WebAssembly 沒概念,建議先讀這裡(中文文章)

2017 年 2 月 28 日,四個主要的瀏覽器一致同意宣佈 WebAssembly 的MVP 版本已經完成,它是一個瀏覽器可以搭載的穩定版本。

WebAssembly 系列(六)WebAssembly 的現在與未來

它提供了瀏覽器可以搭載的穩定核,這個核並沒有包含 WebAssembly 組織所計劃的所有特徵,而是提供了可以使 WebAssembly 穩定執行的基本版本。

這樣一來開發者就可以使用 WebAssembly 程式碼了。對於舊版本的瀏覽器,開發者可以通過 asm.js 來向下相容程式碼,asm.js 是 JavaScript 的一個子集,所有 JS 引擎都可以使用它。另外,通過 Emscripten 工具,你可以把你的應用編譯成 WebAssembly 或者 asm.js。

儘管是第一個版本,WebAssembly 已經能發揮出它的優勢了,未來通過不斷地改善和融入新特徵,WebAssembly 會變的更快。

提升瀏覽器中 WebAssembly 的效能

隨著各種瀏覽器都使自己的引擎支援 WebAssembly,速度提升就變成自然而然的了,目前各大瀏覽器廠商都在積極推動這件事情。

JavaScript 和 WebAssembly 之間呼叫的中間函式

目前,在 JS 中呼叫 WebAssembly 的速度比本應達到的速度要慢。這是因為中間需要做一次“蹦床運動”。JIT 沒有辦法直接處理 WebAssembly,所以 JIT 要先把 WebAssembly 函式傳送到懂它的地方。這一過程是引擎中比較慢的地方。

WebAssembly 系列(六)WebAssembly 的現在與未來

按理來講,如果 JIT 知道如何直接處理 WebAssembly 函式,那麼速度會有百倍的提升。

如果你傳遞的是單一任務給 WebAssembly 模組,那麼不用擔心這個開銷,因為只有一次轉換,也會比較快。但是如果是頻繁地從 WebAssembly 和 JavaScript 之間切換,那麼這個開銷就必須要考慮了。

快速載入

JIT 必須要在快速載入和快速執行之間做權衡。如果在編譯和優化階段花了大量的時間,那麼執行的必然會很快,但是啟動會比較慢。目前有大量的工作正在研究,如何使預編譯時間和程式真正執行時間兩者平衡。

WebAssembly 不需要對變數型別做優化假設,所以引擎也不關心在執行時的變數型別。這就給效率的提升提供了更多的可能性,比如可以使編譯和執行這兩個過程並行。

加之最新增加的 JavaScript API 允許 WebAssembly 的流編譯,這就使得在位元組流還在下載的時候就啟動編譯。

FireFox 目前正在開發兩個編譯器系統。一個編譯器先啟動,對程式碼進行部分優化。在程式碼已經開始執行時,第二個編譯器會在後臺對程式碼進行全優化,當全優化過程完畢,就會將程式碼替換成全優化版本繼續執行。

新增後續特性到 WebAssembly 標準的過程

WebAssembly 的發展是採用小步迭代的方式,邊測試邊開發,而不是預先設計好一切。

這就意味著有很多功能還在襁褓之中,沒有經過徹底思考以及實際驗證。它們想要寫進標準,還要通過所有的瀏覽器廠商的積極參與。

這些特性叫做:未來特性。這裡列出幾個。

直接操作 DOM

目前 WebAssembly 沒有任何方法可以與 DOM 直接互動。就是說你還不能通過比如 element.innerHTML 的方法來更新節點。

想要操作 DOM,必須要通過 JS。那麼你就要在 WebAssembly 中呼叫 JavaScript 函式(WebAssembly 模組中,既可以引入 WebAssembly 函式,也可以引入 JavaScript 函式)。

WebAssembly 系列(六)WebAssembly 的現在與未來

不管怎麼樣,都要通過 JS 來實現,這比直接訪問 DOM 要慢得多,所以這是未來一定要解決的一個問題。

共享記憶體的併發性

提升程式碼執行速度的一個方法是使程式碼並行執行,不過有時也會適得其反,因為不同的執行緒在同步的時候可能會花費更多的時間。

這時如果能夠使不同的執行緒共享記憶體,那就能降低這種開銷。實現這一功能 WebAssembly 將會使用 JavaScript 中的 SharedArrayBuffer,而這一功能的實現將會提高程式執行的效率。

SIMD(單指令,多資料)

如果你之前瞭解過 WebAssembly 相關的內容,你可能會聽說過 SIMD,全稱是:Single Instruction, Multiple Data(單指令,多資料),這是並行化的另一種方法。

SIMD 在處理存放大量資料的資料結構有其獨特的優勢。比如存放了很多不同資料的 vector(容器),就可以用同一個指令同時對容器的不同部分做處理。這種方法會大幅提高複雜計算的效率,比如遊戲或者 VR。

這對於普通 web 應用開發者不是很重要,但是對於多媒體、遊戲開發者非常關鍵。

異常處理

許多語言都仿照 C++ 式的異常處理,但是 WebAssembly 並沒有包含異常處理。

如果你用 Emscripten 編譯程式碼,就知道它會模擬異常處理,但是這一過程非常之慢,慢到你都想用 “DISABLE_EXCEPTION_CATCHING” 標記把異常處理關掉。

如果異常處理加入到了 WebAssembly,那就不用採用模擬的方式了。而異常處理對於開發者來講又特別重要,所以這也是未來的一大功能點。

其他改進——使開發者開發起來更簡單

一些未來特性不是針對效能的,而是使開發者開發 WebAssembly 更方便。

  • 一流的開發者工具。目前在瀏覽器中除錯 WebAssembly 就像除錯彙編一樣,很少的開發者可以手動地把自己的原始碼和彙編程式碼對應起來。我們在致力於開發出更加適合開發者除錯原始碼的工具。
  • 垃圾回收。如果你能提前確定變數型別,那就可以把你的程式碼變成 WebAssembly,例如 TypeScript 程式碼就可以編譯成 WebAssembly。但是現在的問題是 WebAssembly 沒辦法處理垃圾回收的問題,WebAssembly 中的記憶體操作都是手動的。所以 WebAssembly 會考慮提供方便的 GC 功能,以方便開發者使用。
  • ES6 模組整合。目前瀏覽器在逐漸支援用 script 標記來載入 JavaScript 模組。一旦這一功能被完美執行,那麼像 <script src=url type="module"> 這樣的標記就可以執行了,這裡的 url 可以換成 WebAssembly 模組。

總結

WebAssembly 執行起來更快,隨著瀏覽器逐步支援了 WebAssembly 的各種特性,WebAssembly 將會變得更快。


我最近正在寫一本《React.js 小書》,對 React.js 感興趣的童鞋,歡迎指點

相關文章