WebAssembly 的由來

ZKL發表於2018-11-23

Javascript ,也叫Ecma script, 是這傢伙用了 10 天時間趕出來的。。

WebAssembly 的由來

所以,各位程式猿們,如果你覺得老闆 10 天要你們上線一個 App 是一個喪心病狂的事情,那麼可以多想想這位哥。

Youtube 上有位哥的採訪,你可以聽聽大神當年的故事。

https://www.youtube.com/watch?v=IPx…當然,碼農和大神的區別在於:遇到這種事情,10 天以後碼農死掉了,而大神成功了。

只是但凡這種極速上線的事情,都會留下一堆的坑,大神和碼農的的區別,也就是水窪和天坑的區別。

這個是坑列表:

  • Javascript 從最開始設計,就是一種解釋型語言,因為大神覺得讓 Javascript 的目標使用者- “非專業程式設計人員和設計師”,瞭解什麼是編譯器是一件很殘忍的事情。
  • 型別自然也是沒有的,因為學習型別就要學習 CPU 工作原理, 學習 CPU 工作原理就要學習組成原理, 大神覺得,讓 “非專業程式設計人和設計師” 去了解 1 和 1.0 一個是 CPU 上處理, 一個是 FPU 上面處理這種顯而易見的現象是一件很殘忍的事情。
  • 物件模型是驚人的奇葩,那是因為不想設計得和 Java 一樣強大, Netscape 當初想法是主要工作都是 Java 來完成,只有輕量級的簡單操作留給 Java script, 做為一種膠水語言( glue langurage). 現在知道為什麼叫 Java script了吧? 一個是Java, 一個是和Java 配合的 Script (指令碼)。 之前還叫過Live script, 因為指令碼和 Java 互動的技術叫 Live connect.
  • 對於泛型, 預設引數,操作符過載, 異常 等等這些黑科技, 大神的回答通通是:

WebAssembly 的由來

好吧,異常後來加上去了。
如果故事到此為止,其實不算一個悲傷故事,大神 10 天時間完成預定目的,東西也釋出了,市場反應也不錯。

但是問題是,市場反應實在是太好了,好得 Javascript 一路竄紅,紅得各大瀏覽器廠商紛紛支援, 成為瀏覽器裡面事實上的官方語言。 在這個過程中, 還順手幹掉了 VB script,

於是這個當初為 “非專業程式設計人員和設計師” 的解釋型語言現在居然變成網際網路上面最重要的語言之一,被用來做各種之前想也不敢想的東西,甚至還有人不顧死活的拿他來做WebOS.

於是這個時候,之前所有的小水窪都變成了天坑。之後很長段時間 JS 領域的發展史,都可以說是填坑史。

其中最大的一個坑,就是效能。

效能填坑階段一

Javascript 一開始就是解釋性語言,解釋性語言的一大特點就是慢, 而網頁應用越來越複雜,如果點個按鈕要等幾秒鐘,那淘寶的秒殺就要變成10秒殺了。這個當然不能忍。 於是聰明的人類想到一個辦法,雖然你是解釋型語言,但是我可以偷偷的編譯你啊。 這個也不需要讓這幫 “非專業程式設計人員和設計師” 們知道, 我只要在程式執行前的一剎那,編譯即將執行的程式碼就好。你看我機不機智。

於是 Google 在 2009 年在 V8 中引入了 JIT 技術 (Just in time compiling 江湖人稱即時編譯)。 有了這個buff, Javascript 瞬間提升了 20 - 40 倍的速度。直接導致一大波大型網頁應用的出現。從此 Javascript 一騎絕塵, 飛黃騰。。呃, 好像哪裡不對嘛?

人類的效能的期望是無窮無盡的,JIT 的帶來的效能提升很快就榨乾了。實際上 JIT 有以下問題:

  • JIT 基於執行期分析編譯,而 Javascript 是一個沒有型別的語言,於是, 大部分時間,JIT 編譯器其實是在猜測 Javascript 中的型別,舉個例子:

WebAssembly 的由來

JIT 看到這裡, 覺得好開心, 馬上把 add 編譯成

WebAssembly 的由來

可是你隨後又幹了這樣一個事情

WebAssembly 的由來

JIT 編譯器的表情肯定是

WebAssembly 的由來

怎麼辦, 已經編譯成機器碼了啊。

  • 這種情況下,JIT 編譯器只能推倒重來。JIT 帶來的效能提升,有時候還沒有這個重編的開銷大。
    有很多的情況下面, JIT 編譯器都無法生成程式碼,比如異常, 比如 for in , 這個基本上是實現難度引起的,具體可以參考: Optimization killers · petkaantonov/bluebird Wiki · GitHub
  • 事實上,大部分時間 JIT 都不會生成優化程式碼,有位元組碼的,直接位元組碼,沒有位元組碼的,粗粗編譯下就結了,因為 JIT 自己也需要時間,除非是一個函式被使用過很多遍,否則不會被編譯成機器碼,因為編譯花的時間可能比直接跑位元組碼還多。

於是,整體上 Javascript JIT 提高的效能到達的天花板還是不高的,雖然是提高了 20 - 50倍,那只是因為之前解釋執行實在是太慢了。。

效能填坑階段二。

既然 JIT 遇到的問題是型別不確定問題和有一些語言功能,比如異常,for in , JIT 起來很麻煩, 我可不可以搞個方法讓使用者不去用這些功能,同時讓他們把用的型別都標註出來啊。

按照這個思路, 催生了兩種實現路徑:

  • 一種是 Typescript, Dart, JSX 為代表的,基本思想是, 我搞個其他的語言,這個語言是強型別的,所以程式猿們需要指定型別,然後我把它編譯成 Javacript 不就行了嘛。強型別的語言編譯成弱型別還不容易,什麼,不知道怎麼編? 把型別去掉就行了嘛。
  • 另一種是火狐的 Asm.js 為代表的, 做一個 javascript 子集, 同時試圖利用標註的方法,加上變數型別, 如果覺得好難理解,這就是個典型的例子:

WebAssembly 的由來

加上一堆沒有什麼卵用提示 x 其實是個 int, 然後有一個能夠識別這些符號的JS引擎,你就可以不用猜型別了哦, 事實上,由於有了型別,連傳統的 AOT 都成為了可能

(Ahead of time, 不懂的話,想象一下,就是和 C/C++ 那種編譯方式就好了)。
如果你沒有注意到,第二種的速度提升潛力比第一種要大非常多。因為第一種,無論如何,也是就是讓JIT (即時編譯) 快一點, 第二種那可直接就編譯了啊 (AOT).

這個是 Asm.js 相對於 JIT 和原生的效能對比

WebAssembly 的由來

同時大家有沒後注意到,這個不是原生程式碼哦, 效能堪比原生程式碼, 安全性和傳統 Javascript 完全一樣。 (尼瑪,你讓外掛們怎麼活)。Web Assembly 就是第二種方式,說到底,Mozilla, Google, Microsoft, and Apple 覺得 Asm.js 這個方法有前途,想標準化一下,大家都能用。

有了大佬們的支援,Web Assembly 比 asm.js 要激進很多。 Web Assembly 連標註 Js 這種事情都懶得做了,不是要 AOT 嗎? 我直接給位元組碼好不好?(後來改成 AST 樹)。對於不支援 Web Assembly 的瀏覽器, 會有一段 Javascript 把 Web Assembly 重新翻譯為 Javascript 執行, 這個技術叫 polyfill, HTML5 剛出來的時候很常用的一個技術。

使用 AST 的原因是因為 AST 比位元組碼更容易壓縮,也更容易翻譯。

不瞭解 AST 可以看下面這張圖, 說明 Javascript 引擎的執行過程。 Javascript 先編譯為 AST, 然後到 Bytecode. AST 的抽象程度比 Bytecode 要高一級。

WebAssembly 的由來

總結來說, Web Assembly 的工作方式如下:

WebAssembly 的由來

好處是:

  • 大幅度提高 Javascript 的效能,希望能把效能這個坑填完,同時也不損失安全性。Webapp 和 原生 App 的效能差距變得很小。
  • 基本之前需要外掛來提高速度這種技術已經沒有必要了, 網頁應用的移植性會變得更好。
  • 感謝@easing 提醒, WebAssembly 其實允許任何語言編譯到它制定的AST tree, 這樣子,各位就可以開開腦洞了, 因為,你可以用C/C++寫網頁了。。

PS: 這個技術我大 Opera 居然沒有參與,今天去申請了進入這個 W3C 討論組,有訊息再放給大家。 

---- 轉載自羅同學的知乎回答,感覺寫的超棒就節選了,以下是作者資訊:

作者:羅志宇

連結:www.zhihu.com/question/31…

來源:知乎


相關文章