釘釘的 H5 性能優化方案

USASam 8年前發布 | 18K 次閱讀 CSS 性能優化 HTML5 前端技術

對于一個H5的產品,功能無疑很重要,但是性能同樣是用戶體驗中不可或缺的一環。原本H5的渲染性能就不及native的app,如果不把性能優化做起來,將極大地影響用戶使用產品的積極性。

用戶感受

當用戶能夠在1-2秒內打開H5頁面,看到信息的展示,或者能夠開始進行下一步的操作,用戶會感覺速度還好,可以接受;而頁面如果在2-5秒后才進入可用的狀態,用戶的耐心會逐漸喪失;而如果一個界面超過5秒甚至更久才能顯示出來,這對用戶來說基本是無法忍受的,也許有一部分用戶會退出重新進入,但更多的用戶會直接放棄使用。

一秒鐘法則

移動互聯網的架構、通訊機制,與有線網絡有著巨大的差異,這也給H5的開發帶來了很大的挑戰。

這是一張手機端接入服務器的流程。

首先,手機要通過無線網絡協議,從基站獲得無線鏈路分配,才能跟網絡進行通訊。 無線網絡基站、基站控制器這方面,會給手機進行信號的分配,已完成手機連接和交互。 獲得無線鏈路后,會進行網絡附著、加密、鑒權,核心網絡會檢查你是不是可以連接在這個網絡上,是否開通套餐,是不是漫游等。核心網絡有SGSN和GGSN,在這一步完成無線網絡協議和有線以太網的協議轉換。 再下一步,核心網絡會給你進行APN選擇、IP分配、啟動計費。 再往下面,才是傳統網絡的步驟:DNS查詢、響應,建立TCP鏈接,HTTP GET,RTTP RESPONSE 200 OK,HTTP RESPONSE DATA,LAST HTTP RESPONSE DATA,開始UI展現。

可見,通過運營商的網絡上網,情況比較復雜,經過的節點太多;運營商的網絡信號強度變化頻繁,連接狀態切換快;網絡延遲高、丟包率高;網絡建立連接的代價高,傳輸速度快慢不等(從2G到4G,相差很大)。

而我們優化的目標,就是所謂的一秒鐘法則,即達成以下的標準:

  • 2g網絡:1秒內完成dns查詢、和后臺服務器建立連接

  • 3g網絡:1秒內完成首字顯示(首字時間)

  • wifi網絡:1秒內完成首屏顯示(首屏時間)

優化方案

★ 資源加載

首屏加載

用戶從點擊按鈕開始載入網頁,在他的感知中,什么時候是“加載完成”?是首屏加載,即在可見的屏幕范圍內,內容展現完全,loading進度條消失。因此在H5性能優化中,一個很重要的目的就是盡可能提升這個“首屏加載”的時間,讓它滿足“一秒鐘法則”。

按需加載

首先要明確,按需加載雖然能提升首屏加載的速度,但是可能帶來更多的界面重繪,影響渲染性能,因此要評估具體的業務場景再做決定。

Lazyload

Lazyload,即延遲加載,這并不是一個新的技術,在PC時代也是非常常用的一種性能優化手段。這個方案的原則是讓屏幕外,或者不影響整體效果顯示的圖片、背景等資源,在界面就緒之后再進行網絡加載。

滾屏加載

滾屏加載是一種常見的無刷新動態加載數據的方案,通常用在列表形式數據展示中。一方面,數據不是通過翻頁進行加載,這樣就避免了再一次請求和渲染整個頁面;另一方面,數據顯示的數量是受限的,例如第一次只請求了10條數據,也就只需要渲染這10條數據,下拉滾屏的時候,再去獲得下面10條數據。

Media Query(響應式加載)

響應式設計是現在網站設計的一個流行趨勢,隨著移動互聯網的發展,這項技術也越來越受到重視。通過這項技術,我們能夠方便地控制資源的加載與顯示,例如說在分辨率不同的手機上,分別使用不同的css,加載不同大小的圖片資源。 方案參考:http://www.poluoluo.com/jzxy/201206/167034.html

第三方資源異步加載

第三方資源有的時候不可控,比如說頁面統計、地圖顯示、分享組件等,這些第三方資源使用的時候要慎重選擇,充分考察它們對于性能的影響,使用異步加載的方式進行,防止第三方資源的使用影響到頁面本身的功能。

Loading進度條

在加載時間較長的時候,務必要讓用戶明確感知到加載完成的提示,通常是在加載過程中顯示Loading的進度條,加載完成的時候隱藏它。從心理上,這會讓用戶有一種“期盼感”,而不至于太過枯燥。

對于一些重量級的H5應用,例如游戲,開始前需要加載很多資源才能讓后面的游戲過程更為流暢,一個帶百分比進度顯示的進度條就更加重要。

避免30*/40*/50*的http status

  • 200是一個正常的response,我們在瀏覽器中打開一個網頁(后面會講如何針對移動端進行調試),還會看到304,即命中瀏覽器緩存。這兩種狀態是正常的http status。

  • 302、301跳轉是常見的跳轉,尤其前一種,在我們進行鑒權的時候有時會用到,但這個做法要盡可能地優化,一個頁面訪問,最多只進行一次302跳轉即可,切忌頻繁地跳轉。

  • 404、500,我們對自己開發的代碼比較注意,一般不會發生,但是有的時候,加載第三方庫,尤其是第三方庫中有自己load組件的操作,這時,404和500錯誤可能會在你不知不覺的時候發生。例如釘釘的第三方微應用中,就遇到過dojo的組件加載問題,加載的一些子組件失敗了,但是又沒有影響頁面顯示,這就很容易被忽略。后面也會再講,如何去測試和發現這樣的隱患。

Favicon.ico

如果我們沒有設置圖標ico,則會加載默認的圖標:域名目錄下的favicon.ico。很多開發者沒有注意到這一點,就會導致這個請求404或者500。

通常,我們在應用內部打開網頁,不會顯示這個圖標出來(除非放到瀏覽器中顯示網頁),我們需要保證這個圖標存在,盡可能地小(一般4KB以下),并且設置一個較長的緩存過期時間。

★圖片的使用

格式選擇

顯示效果較好的圖片格式中,有webp、jpg和png24/32這幾種常見的圖片格式。一般來說,webp的圖片最小,但在iOS或者android4.0以下的系統中可能會有兼容性問題需要解決。

  • Jpg是我們最常使用的方案,大小適中,解碼速度快,兼容性問題也基本不存在,是我們在H5的應用中使用起來性價比最高的方案。

  • Png24或png32,一般來說,顯示效果肯定會比jpg更好,但是實際上人眼很難感知出來,所以在H5應用中要避免這種格式的大圖片。

對于少量的圖片,推薦用智圖或者tinypng等工具來幫助自己選擇合適的大小、格式。

像素控制

在H5應用中,圖片的像素要嚴格控制,一般來說不建議寬度超過640px。

小圖片合并

在html網頁中,如果有多個小圖片需要加載,不妨試試CSS Sprites方案,尤其是一些基本不變,大小差不多的操作類型圖標。

避免html代碼中的大小重設

在html或者css中,如果有類似width: **px這樣的代碼,就要注意看一看了,如果說圖片顯示的效果是寬度100px,而下載的圖片卻是200px寬度,那這大小基本上就是所需要的4倍面積了,所以在H5應用中,使用圖片的一個原則就是需要顯示成多大,就下載多大的資源。

避免DataURL

DataURL是用Base64的方式,將圖片變成一串文本編碼放入代碼的方式。這種方式有好處,因為它可以減少一次http交互的請求,對于一些體積特別小的圖片,或者是動態生成的圖片可以考慮使用。但在H5應用中,一般情況下,我們都是需要避免DataURL的,因為它的數據體積通常比二進制圖片的格式大1/3,而且它不會被瀏覽器緩存,每次頁面刷新都需要重新加載這部分數據。

使用圖片的替代(css3, svg, iconfont)

CSS3和svg可以更好地使用GPU進行渲染加速,而且會避免增加圖片資源導致的http請求增加。例如一些div的圓角效果,就完全可以用用css來實現。

Iconfont,可以認為是一種矢量類型的操作字體。如果頁面中有較多的操作圖標,可以考慮使用iconfont來替代圖片資源。

★域名/服務端部署

Gzip

服務端要開啟Gzip壓縮。

資源緩存,長cache

合理設置資源的過期時間,尤其對一些靜態的不需要改變的資源,將其緩存過期時間設置得長一些。

分域名部署(靜態資源域名)

將動態資源和靜態資源放置在不同的域名下,例如圖片,放在自己特定的域名下。這樣的好處是,靜態資源請求時,不會帶上動態域名中所設置的cookie頭信息,從而減少http請求的大小。

減少Cookie

盡量減少Cookie頭信息的大小,因為這部分數據使用的是上行流量,上行帶寬更小,所以傳輸速度更慢,因此要盡量精簡其大小。

CDN加速

部署CDN服務器,或者使用第三方的CDN加速服務,優化不同地域接入網站的帶寬速度。

★ 代碼資源

Javascript, CSS合并

盡量將所有的js和css合并,減少資源請求的次數。

外聯使用js, css

外聯使用js和css,這樣可以有效地利用緩存,避免html頁面刷新后重新加載這部分代碼。

壓縮html, js, css

壓縮代碼,尤其是js和css資源,壓縮后的大小可以降低至原來的1/3以下,有效節約流量。

資源的版本更新

庫js、css通常不會更新,但是我們的業務js和css可能會有更新,如果命中瀏覽器緩存,可能會讓一些新的特性不能及時展現,甚至可能導致邏輯上的沖突。

因此對于這些js、css的資源引入,最好用版本號或者更新時間來作為后綴,這樣的話,后綴不變,命中緩存;后綴改變,瀏覽器自動更新最新的代碼。

Css位置

CSS要放到html代碼的開頭的head標簽結束前。如果網頁是動態生成的,那么在head代碼完成后可以強制輸出(例如php的flush()操作),這樣的話,瀏覽器就會更快地解析出來head中的內容,開始下載css文件資源。

Js位置

Js放到前,這樣的話,js的加載不會影響初始頁面的渲染。

★代碼規范

避免空src

圖片設置為空的src地址,在某些瀏覽器中可能會導致增加一個無效的http請求,因此要避免。

避免css表達式

可能會讓頁面多次執行計算,造成卡頓等性能問題。

避免空css規則

降低css渲染計算的成本

避免直接設置元素style

直接設置style屬性,一方面在html代碼中不利于緩存,另一方面也不利于樣式的復用,因此要避免,通過指定id或者class的方式,在css代碼塊中進行樣式調整。

★ 服務端接口

接口合并

如果頁面需要請求兩部分以上的數據接口,建議將其合并,否則會增加一次http請求。

減少接口數據量

有的時候,服務端會把一些無關緊要的數據返回回來,尤其是類似于更新時間、狀態等信息,如果在客戶端不影響內容的邏輯展示,不妨在接口返回的數據中直接去掉這些內容。

緩存

緩存接口數據,在一些數據新舊敏感性不高的場景下很有作用,在非首次加載數據時候優先使用上次請求來的緩存數據,可以讓頁面更加快速地渲染出來,而不用等待一個新的http請求結束之后再渲染。這一點我們在后面還會再次提及。

★ 其他一些建議

  • 合理使用css

    • 正確使用Display屬性 Display屬性會影響頁面的渲染,因此請合理使用

    • display:inline后不應該再使用width、height、margin、padding以及float

    • display:inline-block后不應該再使用float

    • display:block后不應該再使用vertical-align

    • display:table-*后不應該再使用margin或者float

    • 不濫用float

    • 不聲明過多的font-size

    • 值為0時不需要單位

    • 標準化各種瀏覽器前綴

    • 無前綴應放在最后

    • CSS動畫只用 (-webkit- 無前綴)兩種即可

    • 其它前綴為 -webkit- -moz- -ms- 無前綴 四種,(-o-Opera瀏覽器改用blink內核,所以淘汰)

  • 選擇器

    • 避免讓選擇符看起來像是正則表達式。高級選擇器不容易讀懂,執行耗時也長

    • 盡量使用ID選擇器

    • 盡量使用css3動畫

  • 資源加載

    • 使用srcset

    • 首次加載不超過1024KB(或者可以說是越小越好)

  • html和js

    • 減少重繪和回流

    • 緩存dom選擇和計算

    • 緩存列表.length

    • 盡量使用事件代理,避免批量綁定事件

    • 使用touchstart,touchend代替click

    • Html使用viewport

    • 減少dom節點

    • 合理使用requestAnimationFrame動畫代替setTimeOut

    • 適當使用Canvas動畫

    • TouchMove, Scroll事件會導致多次渲染

★ 更快一步

前面的很多建議與普通的PC端web網頁的開發是一致的,但是在移動互聯網應用下,僅僅做到這些,可能只有60分,那么怎樣才能得到80分甚至更高?

單頁應用

釘釘的審批微應用,使用的就是單頁架構。在這種架構下,基本不存在頁面跳轉的等待時間,只需要執行js邏輯觸發界面變化,最多進行一次網絡請求,獲得服務端數據,其他資源均不需要再次請求。

資源離線

再快的網絡交互,畢竟也是跨越了數個網絡節點,因此一張圖片、一個js,優化到了極致,也照樣可能需要幾百毫秒的時間來獲得。因此想要打破這個極限,就要使用資源離線的策略。

在釘釘的微應用中,就使用了這樣的一個“離線包”策略。一些固定的圖片、js庫等,被打包放入app中(或根據需要,在app啟動的時候進行下載更新)。

微應用中,網頁代碼里面加載網絡資源的需求,就變成了直接加載本地文件,速度自然得到再一次巨大的提升。

本地數據持久化和更新機制(版本管理)

對于一些時效性沒有那么高的數據,可以考慮將接口數據緩存。那么頁面的渲染將變成這樣的流程:

而非首次進入界面,流程如下:

可以看出,在非首次進入界面的時候,頁面不需要等待網絡數據返回,就可以進行界面渲染,渲染的初始數據來自于本地的緩存,頁面可以“秒開”。而當服務端的數據返回之后,本地的渲染會再次更新,緩存也被更新。

采用這樣的方案有利有弊,好處顯而易見,首屏加載的速度簡直太快了——靜態資源來自本地,數據接口來自本地,這在2G、3G或者其他網絡速度較慢的時候,也可以讓用戶在極短的時間內就看到內容。但是這種方案也并非萬能。

  1. 首次加載不可避免,還是會請求網絡。

  2. 服務端有更新的時候,客戶端不能夠快速感知,頁面可能還停留在一個“舊的版本”上,尤其是網絡速度較慢時,可能還是需要經過好幾秒,頁面才會更新至最新版本。因此如果應用對數據的新舊很敏感的話,這種方案就不適合

  3. 數據更新后,需要重新渲染界面,界面刷新的性能消耗比正常情況更多,而且增加了程序的復雜度,容易出錯。

預加載

有時,我們能夠通過用戶的行為統計,預判出用戶下一步可能進行的操作。假設,我們統計出來針對某個微應用,用戶首頁渲染完成之后,大部分會點擊列表中的第一個項目查看詳情。那么在首頁渲染完成之后,我們就可以先預先加載第一個項目的部分內容,那么針對這部分用戶,他們實際點擊之后,立即就能看到新的頁面中的內容。

當然,這個方式也并不是在所有場景下都使用。一方面,需要做好充分的用戶調研,掌握用戶的使用習慣;另一方面,對于小部分用戶而言,預加載所帶來的就是不必要的流量消耗。

經典案例

★ 圖片未優化

通過charles可以方便地進行測試。 從請求監控的情況看,有一張圖片超過了60KB,寬度640px,但是在應用中,實際顯示的是一張小縮略圖,是通過代碼控制讓它顯示成小圖的,因此修改方案很簡單,將所有頭像的圖片均改為獲取120px寬度的即可。

★按需加載

  • 釘釘的教學頁面

    • 多個slide頁面, 每個頁面有2-3個圖片, 其中有一個是大圖顯示

    • 圖片是客戶提供的, 最大的圖片大約是300KB以上

    • 第一次進入頁面后, 所有slide的圖片均進行加載

    • 3G網絡下, loading的圖標大約持續6000ms后才會消失

  • 優化方案

    • 盡可能優化圖片, 但是壓縮后發現噪點明顯增加, 影響了顯示效果

    • 修改加載方案, 第一次進入后, 只加載本頁的圖片

    • loading時間降低至1秒左右

 

 

來自:http://mp.weixin.qq.com/s/r-D4S94XOo22PQM_wZlrig

 

 本文由用戶 USASam 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!