關於移動Web效能的5個誤傳

發表於2013-08-09

譯註:英文原文由Sencha的CEO Michael Mullany所寫,主要是回應早前的一篇引起較多關於移動Web效能討論的文章《Why mobile web apps are slow》(原文譯文),作者的主要觀點是《Why mobile web apps are slow》文中給出的資料雖然基本正確,但是對資料的解讀卻存在誤導的成分,並且只考量了JavaScript的效能,而對移動應用來說更關鍵的Graphics效能並沒有被考量在內。並且移動應用效能的提升不僅僅會得益於瀏覽器提升JavaScript的效能,還會得益於更高程度的GPU加速渲染,多執行緒並行化處理等等。

我們最近聽到了一些在不斷重複的關於移動HTML效能的誤傳,但是這並不完全準確。就像那些流傳已久的都市傳說一樣,它們聽起來似乎有理有據,讓人信服。但是這些誤傳是基於不正確的前提,對於原生應用和Web應用的軟體堆疊之間的關係的概念是錯誤的,只是一些因為曲解了資料而推匯出的漫無目的的觀點。

誤傳#1:移動Web效能主要是由CPU主導的JavaScript效能所決定的

真相:大部分Web效能是由瀏覽器對渲染流水線的優化,DOM操作的速度和使用GPU加速的程度來決定的。更快的JavaScript效能的確不錯,但它很少會成為效能的瓶頸。

誤傳#2:依賴CPU的JavaScript效能僅僅因為硬體的提升才變得更快(aka 摩爾定律)

真相:在過去4年裡面50%以上的JavsScript效能的提升是得益於軟體上的優化,而不是硬體上的提升。甚至單執行緒的JavaScript效能還在不斷提升,更不用說現在很多應用開發者通過使用Web Workers來利用多執行緒提升效能。

誤傳 #3:移動瀏覽器最近的效能優化已經基本停滯,未來也沒有更多上升的空間

真相:每一個移動瀏覽器都在一些特定的領域比起其它瀏覽器在效能上有10倍-40倍的提高。Surface的SVG效能比iPhone高30倍。而iPhone的DOM操作效能是Surface的10倍。所以對每個瀏覽器來說,僅僅做到向其它瀏覽器表現優秀的領域看齊,就有很多效能提升的空間。

誤傳 #4:移動應用很難再從未來的硬體效能提升中受益

真相:在過去三年裡,每一次硬體更新換代都會帶來JavaScript效能的飛躍。不但瀏覽器的單執行緒效能仍然在不斷提升,並且還會因為更快的GPU速度,更快的記憶體頻寬,和通過多執行緒並行化處理更充分地利用多核CPU來不斷提升效能。越來越多的瀏覽器已經開始更多地利用並行化來減輕主執行緒的負擔,比如說:Firefox使用了單獨的混合執行緒;Chrome並行化處理HTML解析;還有IE把JavaScript的JIT編譯放到了其它執行緒

誤傳 #5:JavaScript的垃圾收集對移動應用來說是效能殺手

真相:這種說法曾經是正確的,不過現在的狀況已經不太一樣。Chrome在2011年的Chrome 17引入了增量垃圾收集機制Firefox去年也實現了同樣的特性。這個特性將每次GC暫停的時間從200ms降到了10ms —— 相當於丟掉一幀 vs 一個可以明顯感知的停頓。避免垃圾收集事件的確可以顯著提升效能,但是隻有你還在使用桌面Web開發模式或者在一個老舊的瀏覽器上執行,垃圾收集才會成為效能殺手。以我們在Fastbook(一個Facebook HTML5應用的克隆)使用的關鍵技術為例,通過建立一個DOM節點的物件池來回收不再使用的DOM物件並迴圈使用,我們成功避免了建立新物件的開銷,同時也避免了因為刪除舊物件而導致GC。瀏覽器的確很有可能提供了一個效能非常糟糕的垃圾收集器(比如說舊的IE),但這並不是支援垃圾收集的語言比如JavaScript(或者Java)的天生的無法克服的缺陷。

OK:關鍵要素

首先,讓我們回顧一下最基本的概念。從5萬英尺的高度往下看,瀏覽器本身是構建於作業系統之上的一個豐富和複雜的抽象層。而Web應用混合運用標記語言,JavaScript指令碼語言和樣式表,使用這個抽象層來建立應用的體驗。這個抽象層本身需要額外的效能開銷,而開銷的多少很大程度決定於你使用抽象層的哪一部分。抽象層的某些部分更快是因為它們離作業系統的系統呼叫或者某些系統庫的呼叫更近(比如說Canvas2D on MacOS)。另外一些部分會比較慢是因為它們無法直接對映到底層的作業系統,並且它們天生就十分複雜(DOM樹操作,JavaScript物件屬性訪問的原型鏈遍歷)。

很少有移動應用是計算密集型的:沒有誰會試圖在iPhone上計算DNA序列。大多數應用有著一個合理的響應模型。使用者執行一個操作,然後應用會馬上回應一個30fps或者更高幀率的視覺動畫,然後在幾百毫秒之內完成任務。只要應用滿足上面的要求,沒有人會在乎應用基於的抽象層距離最底層的矽晶圓之間到底有多遠。從這點來說,單純地比較原生應用的抽象層和Web應用的抽象層意義並不大。

對於Sencha來說,我們知道一個優秀的開發者使用移動Web技術和基於一個現代的Web框架比如Sencha Touch,是可以建立出優秀的應用體驗的,它執行的足夠快,滿足使用者的期待。並且過去3年的移動效能飛速提升的趨勢也使我們深受鼓舞。我們很樂意跟您在接下來的文章裡分享一些相關的資料。

但是我們的本意並不是說移動Web應用能夠執行的和原生應用一樣快,或者它們能夠在效能上能夠與桌面Web應用相媲美。這不是真實的。移動裝置的硬體效能比起桌面裝置要慢5倍到10倍:CPU效能比較低,快取層次結構過於扁平,缺少多級快取的支援,網路連結的延遲也很高。並且任何軟體抽象層本身(比如瀏覽器)都需要付出額外的開銷。其實這不僅僅是Web應用開發者的問題。iOS原生應用的開發者一樣可以告訴你,當iOS CoreGraphics在第一款視網膜iPad上效能很低的時候,這使得他們相當一部分人不得不拋棄CoreGraphics而直接使用OpenGL。

進一步追溯誤傳的真相

通過過去三年持續對Sencha Touch在資料驅動應用中的使用進行效能優化的經歷,我們可以很自信的說,我們很少會被最原始的JavaScript效能所困擾。僅僅是在構建Sencha Touch佈局系統時,因為Android 2.x的JavaScript效能太差,使得我們改用了Flexbox。

更多時候,我們碰到的問題是DOM操作太慢,瀏覽器渲染引擎效能比較差和垃圾事件堆積過多無法及時處理。而這些侷限基本上都是因為瀏覽器的架構設計者和開發者造成的,跟JavaScript語言和JavaScript引擎本身並沒有本質的聯絡。舉個例子來說,有一次我們和瀏覽器開發者一起優化瀏覽器效能,我們最終在某個特定操作上(顏色屬性的改變)獲得了40倍的效能提高,而這之前是我們的滾動列表實現的效能瓶頸,而類似的例子還有很多。

在iOS和Android上的JavaScript效能

雖然我們說過JavaScript效能其實對於移動裝置來說並不是那麼重要,但是我們還是希望可以推翻它並沒有得到改善的誤傳。下圖是SunSpider測試(越低越好)在iOS上過去4年的得分(按照硬體版本和OS版本劃分)。(很幸運,SunSpider是一個廣泛被應用的測試,所以我們很容易就在網上找到舊的iOS裝置的測試成績)。2009年的時候,當時執行iOS3的iPhone 3GS得分是15,000 —— 非常的糟糕,跟當時的桌面瀏覽器的300-600的得分相差30倍左右。

然而,如果你把iPhone 3GS升級到iOS 4,5和6,你就可以在同樣的硬體上面體驗到4倍的效能提升。(在iOS4到iOS5之間效能的巨大的飛躍主要得益於新的Nitro引擎。)實際上SunSpider成績在iOS7上仍然會有所提高,只是基於保密協議我們這裡就不再多說了。跟今天的桌面瀏覽器相比,最先進的移動瀏覽器大概還有5倍左右的效能差距 —— 比起09年的30倍已經是相當大的改進。

如果需要了解更多關於iOS硬體和軟體效能改進的資訊,可以參考Anandtech去年10月份的評測

在Android平臺上也差不多有相當等級的改進。從我們的測試實驗室,我們找到了一些可以認為是過去3年裡面在當時比較有代表性的高效能機器。我們測試了下面4款手機:

  • 三星Captivate Android 2.2(2010年7月釋出)
  • Droid Bionic Android 2.3.4(2011年9月釋出)
  • 三星Galaxy Note 2 Android 4.1.2(2012年9月釋出)
  • 三星Galaxy S4 Android 4.2.2(2013年4月釋出)

如下圖所示,SunSpider的成績在過去4年的提升非常明顯。從Android 2.x到Android4.x就帶來了接近3倍的提升。

無論是iOS還是Android,這些效能提升都不僅僅是由於摩爾定律本身帶來的。過去3年,如果按照摩爾定律,我們期望獲得的效能提升大概是4倍左右(18個月提升一倍),但實際上卻遠遠不止,所以軟體上的優化的確起了相當大的作用。

更多有意義的測試

如之前我們已經提過的,SunSpider的測試成績其實越來越不重要,因為它跟應用本身的效能要求關係其實並不大。相反,DOM操作的測試,還有Canvas和SVG的測試成績對應用的使用者體驗關係更密切。(理想狀態下,我們應該還要去測量改變CSS屬性的速度,還有CSS動畫,過渡動畫和幾何變換動畫的幀率 —— 因為它們在Web應用中使用的更頻繁 —— 不過由於缺少瀏覽器的支援,仍然無法準確地獲取這些測試資料)

第一個DOM操作測試:我們使用了Dromaeo Core DOM測試。下圖是之前的4臺Android裝置上得到的測試成績,我們把Captivates上的4項Core DOM測試成績(Attributes,Modifications,Query,Traversal)作為1分,其它裝置的測試成績就是相對於Captivates的得分,然後取4項得分的平均值作為最終結果。

如你所見,Android從2.x到4.x帶來了3.5倍的效能提升,雖然S4比起Note2的提升幅度比較小。我們在iOS裝置上也進行了Dromaeo測試。不幸的是,由於iOS無法降級,我們沒法得到老的iOS版本的測試成績,不過我們仍然可以看到隨著硬體的升級,Dromaeo測試效能一樣是穩步上升。並且有趣的是,不同的iOS6裝置之間的Dromaeo效能提升幅度要大於它們的CPU速度提升幅度,這說明了記憶體頻寬或者快取的速度提升肯定帶來了更大的幫助,所以才能比單純依靠摩爾定律所能獲得的結果更好。

為了顯示瀏覽器還有多少潛在的效能提升空間(僅僅是為了趕上其它瀏覽器表現優異的領域),我們還測試了Surface RT。IE槽糕的DOM操作效能一直困擾著我們,但這說明了Surface RT上的IE10在DOM操作上還有很大的改善空間。這也是我們之前打破的一個誤傳 —— “移動裝置的軟體堆疊本身已經足夠好,未來沒有太多的優化空間”。起碼對於Windows RT來說,在DOM操作上還有10倍的差距需要去填補。(我們後面還會展現在哪些測試上,iOS表現不佳)

圖形效能

除了展現JavaScript和DOM操作效能的巨大提升外,我們還想為您展現瀏覽器在Canvas和SVG上的效能提升。我們之前就發現了Canvas2D效能在同樣硬體上iOS5比iOS4提升了5-8倍。甚至當iPad 2升級到iOS5後,一些區域性測試提升了80倍。並且因為Canvas實際上是對iPhone上的CoreGraphics API的直接呼叫,所以當原生圖形效能獲得提升時,Canvas效能也獲得了同樣的提升。在下面的測試中,我們使用了mindcat Canvas2D benchmark來測試效能。這裡,我們看到了隨著iPhone硬體的提升(都執行iOS6),Canvas效能也在不斷提升。

?

請牢記,上圖的顯示的資料已經計入了iOS4到iOS5的效能飛躍。如你所見,上圖顯示出歷代iPhone在Canvas2D上的效能提升達到了7倍之多,遠比它們的CPU速度提升幅度要大(按照摩爾定律CPU最多也就提升了4倍),這也反映了iPhone的軟體堆疊充分利用了CPU/GPU來提升自身的效能。移動Web效能的提升實際上有很大一部分是受益於GPU效能的提升和瀏覽器更多使用GPU進行圖形加速。

我們再來看看在Android上執行同樣的測試,我們看到一些有趣的資料顯示Android上Canvas效能跟CPU效能之間並沒有必然的聯絡。從Android 2.x到Android 4.x上的效能飛躍主要是因為2.x的Canvas完全沒有使用GPU加速。這再次說明了,僅僅是瀏覽器充分利用GPU加速就能夠帶來巨大的效能提升。

SVG測試

SVG是另外一個可以展現Web效能的廣闊的領域。雖然不如Canvas流行(很大程度是因為Canvas已經足夠快),SVG的效能隨著硬體提升仍然在穩步提升。下圖是來自Stephen Bannasch的一個測試,測試了繪製10,000線段構成的一個SVG路徑所需的時間。再一次,測試結果顯示了各代iPhone CPU/GPU效能提升帶來的穩定的SVG效能提升(所有的iPhone都執行iOS6)。

?

但是最大的差距還是源於軟體本身:Surface RT比iPhone 5快了30倍(對比iPad4也是如此,雖然這裡我們沒有列出來)。實際上,Surface RT比起執行在我一年前買的Macbook上的Safari仍然快了10倍!這個差距是是否使用了GPU加速造成的,Window 8/IE10在SVG上充分利用了GPU進行加速,才獲得瞭如此驚人的成果。只要瀏覽器開發者把更多原來由CPU完成的工作轉移到GPU上面去,我們就有可能在iOS和Android上也看到同樣的效能提升。

除了上面的長路徑繪製外,我們還執行了另外一個來自Cameron Adams的SVG測試,測試了500個不斷反彈的小球的動畫幀率。再一次,我們可以看到由硬體提升所帶來的SVG效能的穩步提升。

比起單純的效能資料,最終的fps值更讓人感興趣。一旦動畫超過了30幀,你就可以得到一個跟電影動畫(24fps)相似的結果,這樣的流暢度已經基本上可以讓觀看者滿意。如果能夠達到60幀,那你就會獲得由GPU加速帶來的極致流暢的體驗。

真實世界的效能:垃圾收集,動態語言和更多

我們希望之前的移動效能探索之旅已經說明了一些事情,也打破了一些誤傳。我們希望為您展現下列真相:

  • JavaScript的效能持續地快速提升
  • 效能的提升由硬體提升和軟體優化同時驅動
  • 雖然高效能的JavaScript是一件好事,但實際上大部分Web應用的效能跟JavaScript效能的關係甚少
  • 幸運的是,其它影響Web應用效能的領域,像DOM操作,Canvas,SVG的效能也在飛速提升

雖然我們可以展現一些高速攝影機下的動畫測試,不過實際上所有移動Web應用的開發者都清楚,CSS動畫,過渡動畫和屬性修改的效能從Android 2.1開始已經得到極大的提高,並且它們還在不斷提高。

之前我們已經澄清了一些不真實的論斷,現在再讓我們做一個最終的說明。我們不斷聽到的各種傳言彙總而成的最終結論是“移動Web應用總是很慢,這是因為JavaScript是一種低效能的動態語言,並且垃圾收集機制對效能是一個極大的傷害”。應該說這個結論本身並不是完全錯誤的。不過如果你的Web應用使用類似Sencha Touch這樣的框架來動態產生DOM內容,一個很大的優勢在於,我們會在瀏覽器之上,在特定的應用上下文下,合理地去管理物件的建立和銷燬,包括事件物件。這樣即使你的應用需要展現無窮盡的資料內容(通過表格,列表或者轉盤),我們通過回收DOM物件,過濾多餘的事件,對要執行的動作進行優先順序排序等優化,可以幫助您的應用獲得60fps的視覺動畫體驗。

如果沒有一箇中間層進行類似的間接處理,的確很容易得到非常糟糕的移動Web應用體驗 —— 就像Facebook移動Web應用的第一個版本一樣。我們相信如果應用直接使用類似jQuery Mobile這樣直接操作底層DOM模型的UI框架時,在可見的未來的確會持續受到效能相關問題的困擾。

彙總

文中包含了大量的資料和覆蓋了不同的主題,最後在這裡讓我們再總結一下。如果您是一位開發者,您應該可以從這篇文章瞭解到:

  • 移動平臺的速度不及桌面平臺的1/5 — 較慢的CPU,還有受限的記憶體大小和速度和較慢的GPU等等。這些都是無法改變的事實。
  • 移動平臺的JavaScript + DOM的訪問速度越來越快,但是你始終應該把iPhone 5看作跟2008年在桌面電腦上執行的Chrome 1.0一樣 (即比桌面版的IE8快5-10倍)。
  • 移動Web應用的圖形效能隨著瀏覽器更多使用GPU進行圖形加速和其它通用軟體優化,已經基本可以實現30幀每秒的動畫。
  • 垃圾收集和平臺渲染效能有限的問題仍然會使你困擾,所以使用一個類似Sencha Touch這樣的抽象框架來獲得更佳效能是十分有必要的。
  • 充分利用移動Web平臺提供的遠端偵錯程式和效能監控能力:像Chrome for Android現在已經提供了一個不錯的fps計數器,還可以顯示需要混合的圖層邊界,這可以告訴你哪些網頁內容實際上已經生成了貼圖並由GPU負責繪製,還有貼圖被載入的次數。

我們希望對這些效能資料的回顧能夠幫助我們打破一些虛假的誤傳。我需要感謝在Sencha的所有人對這篇文章的貢獻,包括Ariya Hidayat 的審閱和提供了大量關於瀏覽器效能優化的文章連結,還有?Jacky Nguyen關於Sencha Touch的抽象層如何進行效能優化的一些實現細節。

 

翻譯後記

喔,終於翻譯完了,以前還沒有翻譯過這麼長的文章,沒想到還真是一件累死人的事情。每一句話都需要斟字酌句細細體會字面下的意思,再用較為通順的中文表述出來,無論是腦力還是體力都是相當大的摧殘,說多了都是淚啊 =_=

應該說要翻譯這篇文章,甚至要讀懂這篇文章,譯者和讀者都需要對瀏覽器核心的一些工作原理有所瞭解。

  • 比如文中多處強調JavaScript RAW performance和DOM Interaction的區別,這是因為雖然DOM Interaction雖然也是由JS去呼叫,但是對瀏覽器來說,實際上JS只是呼叫瀏覽器核心提供的JS Binding API,整個Interaction是由瀏覽器本身去執行的,所以不應該當作JavaScript本身的效能來考量。
  • 又如瀏覽器所構建的抽象層的不同部分直接或者間接對映到OS的系統呼叫或者系統庫呼叫對效能的不同影響的說法要怎麼理解?舉個例子來說,Web應用開發者可以用DOM+CSS或者用Canvas實現同樣的動畫效果,下面分別是基於QuarkJS實現的兩個同樣的動畫,一個基於DOM,一個基於Canvas,對於Canvas繪製直接使用OS本身的2D繪相簿去實現,並且支援GPU加速的瀏覽器來說,Canvas動畫的效率會比使用DOM要高的多,這是因為基於DOM和CSS的動畫,瀏覽器通常需要進行重新計算樣式,重新排版,重新光柵化,重新上傳貼圖,重新混合等這樣一個複雜的流程,效率自然高不起來。再舉一個例子,對於支援圖層混合加速(Accelerated Compositing)和硬體加速的瀏覽器來說,對付CSS Transform這樣的動畫就是小菜一碟,因為對它來說這個動畫就是不斷改變元素所屬圖層的Transform屬性,然後使用GPU重新混合的過程。而支援硬體加速的瀏覽器所謂的圖層混合其實就是通過OpenGL進行貼圖的這樣一個過程。

最後要說的是,文中的一些觀點還是需要在一定的條件下才能成立的,並不是放之四海而皆準,這是讀者需要留意的地方:

  • 大部分Web應用效能跟JavaScript效能關係不大,對它的要求不高

是的,大部分是這樣的,但不見得你的Web應用就是這大部分之一。實際上,對於有一定複雜程度的基於Canvas的Web Game來說,JavaScript效能很有可能成為它的效能瓶頸。這些Web Game的場景通常比較複雜,包含成百甚至上千的繪圖物件(比如實現一個絢麗的粒子效果),需要在JavaScript裡面構建一個成百上千個節點的Scene Graph。每繪製一幀,都意味著需要對這個Scene Graph進行遍歷,訪問每一個節點,更新它的狀態,然後再呼叫Canvas API將它繪製出來。如果要達到30fps的速度,這意味著最多隻有30ms左右的時間來完成每一幀(實際上應該沒有那麼多),即使不算Canvas API本身的繪製開銷,單單是遍歷和狀態更新的操作就很有可能達到幾十毫秒的量級了,特別是狀態更新中包含大量的碰撞檢測和物理運動計算的時候。

  • 通過並行化處理是未來瀏覽器有效提升效能的一個有效手段

應該說,當前通過並行化處理充分利用多核CPU/GPU提升效能是瀏覽器核心技術研究發展的一個熱點。但是並行化並不是銀彈,指望它能夠短期內戲劇性地大幅度提升瀏覽器的整體效能並不現實。

  • 首先對於移動裝置來說,iOS還好,但是Android由於自身的開放性,硬體水平參差不齊,低端硬體還有相當大的保有量,它們缺乏足夠的資源去支援並行化,並行化對它們來說反而更糟糕。不過得益於像MTK這樣的晶片廠商大力提升中低端裝置的效能,現在的千元機效能已經跟幾年前不可同日而言,大概再過多一兩年這個問題應該就不再成為問題了。
  • 其次並行化處理並不是想象中的那麼容易,因為瀏覽器的大部分作業實際上都有某種程度的順序依賴和上下文依賴,需要很多額外的處理才有可能實現部分並行化(畢竟不是資料處理,要做到完全並行化可能性極低)。這樣的並行化需要額外的開銷,並且只適應於部分場景,有一定的侷限性。目前瀏覽器除了網路連結的部分,並行化程度最高的應該就是渲染了,除了圖層混合會執行在獨立執行緒並且主要使用GPU外,像Chrome,Android Browser都把光柵化從主執行緒剝出來,渲染效能的確從並行化中獲益極大,不過也付出了額外的CPU/記憶體開銷的代價。其它領域的並行化進展還是很慢,並且也難見有可能使得效能大幅度提升,比如Chrome在做的HTML解析和樣式計算的並行化,最多也就能夠減少網頁從開始載入到第一次完整呈現的時間,對於整體效能提升意義不大。至於JavaScript,除了IE所實現的JIT並行化外,垃圾收集也是一個有可能剝離出主執行緒的領域,只是我個人對JavaScript引擎瞭解不多,不知道具體的技術難點在哪裡。
  • 最後還需要前端開發者有意識地去使用並行化,或者為了更好地支援瀏覽器的併發作業對自己的應用進行專門優化,比如說Web Workers可以讓部分JavaScript程式碼執行在獨立的執行緒,但在實際的網頁裡面使用的應該很少。

最後的話

作為讀者,如果您能夠一直看到這裡,說明您應該對Web App/Game開發是有著真愛的^_^ ,所以不妨再看完這最後一節。從我個人的開發經驗來看,一個經過充分優化的應用比起沒有經過優化的應用通常會有非常明顯的效能差別,如果您的Web App/Game對效能要求很高,並且主要執行在移動平臺,那麼效能優化對您來說那就更加重要了(移動平臺可沒有那麼多可以揮霍效能的空間)。而為了幫助前端開發者更好地做好效能優化,Chrome提供了可稱為逆天的神器Dev Tools,學會使用這套工具(推薦Code School上面的視訊教程),然後使用它來對您的應用進行效能分析和優化,您會發現這才是真正能夠獲得戲劇性的效能飛躍的最大可能,這也是所謂的“求諸人不如求諸己”。

 

相關文章