作者:Lin Clark
編譯:鬍子大哈
翻譯原文:huziketang.com/blog/posts/…
英文原文:Where is WebAssembly now and what’s next?
轉載請註明出處,保留原文連結以及作者資訊
本文是關於 WebAssembly 系列的第六篇文章(本系列共六篇文章),也同時是本系列的收尾文章。如果你沒有讀先前文章的話,建議先讀這裡。如果對 WebAssembly 沒概念,建議先讀這裡(中文文章)。
2017 年 2 月 28 日,四個主要的瀏覽器一致同意宣佈 WebAssembly 的MVP 版本已經完成,它是一個瀏覽器可以搭載的穩定版本。
它提供了瀏覽器可以搭載的穩定核,這個核並沒有包含 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 函式傳送到懂它的地方。這一過程是引擎中比較慢的地方。
按理來講,如果 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 函式)。
不管怎麼樣,都要通過 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 感興趣的童鞋,歡迎指點。