摘要:所以,關于優化實戰我們主要分為兩部分加載渲染鏈路優化和編程代碼優化。加載渲染鏈路優化從訪問到頁面呈現,整個鏈路可以做優化的思路。資源緩存這一節我們多帶帶介紹緩存,是的,利用好緩存可以解決很多問題,包括頁面加載和渲染的問題都能得到很好的優化。
優化實戰
本文屬于思否課堂VirtualDOM到AST玩轉前端性能原理解析與代碼實戰課程
官方博客:fed123.com
我們已經全面分析總結了評估頁面性能和用戶體驗的各個指標參數。那么怎么來優化呢?open signal官方提供了2018年2月份統計的全世界4G網絡覆蓋率和通信速率的統計分布圖如下,在目前移動互聯網的浪潮下,我們要利用好用戶終端設備的每個字節的流量。
當然頁面性能和體驗優化并不是一蹴而就的,需要不斷的研究、跟蹤,發現問題,解決問題。但是我們可以在一開始編寫業務代碼的時候就做的更好,做到極致。所以,關于優化實戰我們主要分為兩部分:加載渲染鏈路優化 和 編程代碼優化。
從訪問url到頁面呈現,整個鏈路可以做優化的思路。
幸運的是,W3C推薦的Navigation Timing標準中所定義的核心的頁面性能數據,它包含了從上個頁面銷毀到跳轉到當前頁面加載完成每個階段所消耗的時間。在canIuse上查到的兼容性也很好:
利用這個接口可以很方便的幫助我們排查鏈路問題。在Navigation Timing標準中介紹到這個API主要包含兩個接口:PerformanceTiming和PerformanceNavigation,這兩個接口由瀏覽器進行實現和維護,當瀏覽器創建頁面的時候就會把接口定義的相關數據掛載到window.performance.timing和window.performance.navigation這兩個屬性上。我們可以打開一個網頁看一下:
我們把這兩個圖對比一下,就可以很容易的排查出頁面的加載鏈路問題。
打開頁面的第一步是請求頁面的html,這里面涉及TTFB這個綜合指標。同時如果有必要我們也可以統計DNS時間和TCP時間。
DNS時間:主要是根據請求域名查詢到對應主機IP的時間。這個和DNS服務器有關系,也可能和本地緩存有關,如果這個很慢,可以找服務商排查下問題。
TCP時間:tcp是承接http協議的下層協議。主要是路由到主機ip,并建立tcp鏈接的時間。這個時間反應了服務器到用戶客戶端之間鏈路是否通暢,網絡是否通暢。
請求完HTML之后,就開始解析html代碼,按照從上至下、自然順序解析,解析內聯CSS代碼或者加載外鏈CSS腳本,解析內聯Javascript腳本,或者加載外鏈Javascript腳本。由于瀏覽器是單線程的,這些CSS和Javascript腳本很可能就會造成頁面卡頓。參考 瀏覽器線程理解與microtask與macrotask。
加載CDN是內容分發網絡,主要用于緩存靜態資源。CDN服務商一般會在全國各地部署服務,而且帶寬很大,這樣訪問CDN的資源時就可以有較短的路由路徑,而且帶寬也比較大,訪問比較快。
建議最好把html, CSS、JS、font、img這些資源放在CDN上,沒有CDN也可以放在OSS存儲服務上,總之比自己的服務器硬盤快多了,至少服務商會在不同區域做分布式部署
如果沒有錢買CDN服務,那么就盡可能少的加載外聯CSS和JS代碼,注意html頭部可以增加dns-prefetch,減少DNS解析時間
不是在首屏展示的資源,不要立即加載,可以在頁面onload之后加載,或者首屏渲染完成再加載
壓縮CSS、JS、font、img,盡量減少體積,服務端開啟gzip
考慮資源combo請求,減少http請求量,瀏覽器一般都有并發限制, 比如chrome一次6個并發http請求,不同瀏覽器內核可能不一樣。
為了讓瀏覽器更快的解析渲染,我們需要考慮這幾點:
CSS嵌套層級不要太深,不超過3級,避免在最內層使用通配選擇器。參考關于 CSS 選擇器性能
JS腳本不要太復雜,考慮輕量化架構,降低JS復雜性,減少解析時間,盡量不要引用復雜的第三方腳本。
按需加載模塊,按需打包,首頁僅僅加載和執行和首屏相關的腳本。其他腳本延遲加載執行。
考慮依賴的第三方模塊是不是必須,需不需要精簡。
打包優化,code split 和 tree shaken。常用webpack和rollup的優化。
用戶交互相關事件綁定(比如頁面scroll,用戶左右滑動等),添加參數{passive:true},減少瀏覽器事件等待。因為這些事件屬于可阻止事件,瀏覽器不知道用戶會不會阻止,所以需要等待js執行,然后再做響應。添加passive參數,就告訴瀏覽器不用等待了。
IOS8以后的ios支持wkwebview,但是很多app之前用的還是uiwebview,建議轉換成wkwebview,獲得性能的提升(UIwebview在執行JS時會阻塞UI渲染進程,WKwebview不會)。
介紹一下code split的方案: react-loadable
// 未處理 import OtherComponent from "./OtherComponent"; const MyComponent = () => (); // 使用react-loadable按需加載 import Loadable from "react-loadable"; const LoadableOtherComponent = Loadable({ loader: () => import("./OtherComponent"), loading: () => Loading..., }); const MyComponent = () => ();
這個也可以在打包工具統一配置,不用每個模塊都自己寫。
只有瀏覽器盡快渲染出來,用戶才能盡快的可以交互。
數據埋點上面我們梳理了加載到解析渲染過程應該做的事情,那么如果你這些都做好了,發現網頁表現依然不盡人意,那么你就要考慮做一下數據埋點。其實數據埋點在企業項目中也是必不可少的,和性能體驗優化構成閉環。通過數據來發現頁面性能和體驗的問題,更有針對的進行解決。
事實上數據埋點分為三類:
業務埋點,統計諸如pv、uv、點擊率、流失率、轉化率等
大數據埋點,統計與用戶行為相關信息,比如那個用戶點擊了那個商品,上報用戶id和商品id,方便后臺分析用戶和商品的關系,可以用做大數據分析,推薦算法來為用戶推薦商品。
工程埋點,統計工程上的數據信息,比如頁面秒開率,dns時間等,也就是我們上節課總結的性能和體驗數據指標。
資源緩存這一節我們多帶帶介紹緩存,是的,利用好緩存可以解決很多問題,包括頁面加載和渲染的問題都能得到很好的優化。
常見的h5緩存方案有很多種,
通常,與頁面加載性能相關的,有下面幾種緩存,
(1)MemoryCache
MemoryCache,資源存放在內存中,一般資源響應回來就會放進去,頁面關閉就會釋放。內存存取性能可達磁盤緩存性能的100倍,但這還不是MemoryCache的最大優勢,MemoryCache最大的優勢是離排版渲染引擎非常近,可以直接被讀取,甚至無需經過線程轉換。在真實的頁面訪問過程中,獲取資源的時間,磁盤IO僅僅是其中的一部分,更多的時間往往消耗在各種線程拋轉。
(2)ClientCache
ClientCache,客戶端緩存,比如,手淘里的ZCache(離線壓縮包緩存),本質上屬于磁盤緩存。這類Cache的優點是能以相對可控的方式讓資源提前緩存在磁盤,但它也有一系列的成本。比如,它需要一套服務器與客戶端協同的下發更新邏輯,服務器端需要管理下發,客戶端需要提前解壓縮。我們可能覺得提前解壓并不是什么弱點,但如果有一千個離線包,這個問題就比較嚴重了,如果不提前解壓,就無法保證首次訪問性能,如果提前解壓會讓IO非常繁忙,可能會造成客戶端打開時嚴重卡頓。
(3)HttpCache
HttpCache,是歷史比較悠久的緩存,它利用標準的 Cache-Control 與服務器端進行協商,根據標準的規則去緩存或更新資源。它應用非常廣泛,是非常有效果的一種磁盤緩存。它的缺點是完全由瀏覽器按標準規則控制,其它端的控制力度非常弱。比如,某些被HttpCache緩存的靜態資源出問題了,通常只能是改頁面,不再使用出問題的資源,而無法主動清除出問題的資源。參考http請求緩存頭,HTTP協商緩存VS強緩存原理
(4)NetCache
網絡相關的Cache,一般是指DNS解析結果的緩存,或預連接的緩存。DNS預解析和預連接是非常重要的,創建一個Https連接的成本非常大,通常需要600ms以上,也就是說,頁面如果有關鍵資源需要全新建連接,秒開基本是不可能了。
(5)CDN
CDN一般是通過負載均衡設備根據用戶IP地址,以及用戶請求的URL,選擇一臺離用戶比較近,緩存了用戶所需的資源,有較好的服務能力的服務器,讓用戶從該服務器去請求內容。它能讓各個用戶的緩存共享,縮短用戶獲取資源的路徑,來提升整體的性能。
當然,還有其它非常多類型的Cache,比如,
JS相關,V8 Bytecode Cache,字節碼緩存,能極大的減少JS解析耗時,甚至可以提升3-6倍的性能。參考:前端優化系列 – JS解析性能分析
渲染相關,圖片解碼數據緩存,是一塊非常大的內存緩存,約100M,能保證頁面滾動過程可以實時獲取到圖片解碼數據,讓滾動非常流暢。
頁面相關,頁面緩存,Safari的PageCache,Firefox的Back-Forward Cache,UC瀏覽器的WebViewCache,都是一樣性質的緩存,將整個執行過的頁面保存在內存。標準的頁面緩存,進入的條件非常苛刻,大部分情況都無法進入,而且在前進后退的場景才允許使用。
前面介紹了很多理論層面的內容,我們接下來介紹一些實踐優化案例。
(1)預置資源進MemoryCache
在頁面的onPageFinished的回調里面去檢查是否有資源可以預置,如果有,就通過相關接口把資源設置進內核的MemoryCache。我們并不知道用戶即將會訪問什么頁面,如果把大量的資源都預置進內存,而用戶卻沒有使用,那就會造成浪費。另外,資源在內核內存,僅僅是加快了資源的加載速度,頁面的首屏包含非常多非常復雜的流程,某個流程的加速并不一定能帶來整體性能的提升,比如,非關鍵的JS放在內存,可能就會先于一些關鍵JS被提前執行,反而讓首屏更慢。所以,選擇放那些資源進內存也是非常有講究的,能預置的資源一般是 非常關鍵的更新頻率較低的少量公共基礎資源。
對于一般公司來說,沒有能力自己定制webview渲染的內核,可以看下系統默認webview內核有沒有這樣的接口來實現操作MemoryCache預置數據的能力。
(2)預加載資源進HttpCache
預置資源進內存,對加載性能的提升是最明顯的,但成本也是最大的,會占用用戶手機寶貴的內存資源。另外一種預置資源的思路是,提前通過內核去預加載一些資源,資源加載回來之后就直接保存在標準的HttpCache。資源在HttpCache和在客戶端緩存(比如,手淘ZCache)的性能差別不大。但如果資源不能放進ZCache,通過這種方式提前放到HttpCache,也是一種優化思路。
(3)使用WebViewCache極速切換頁面
H5頁面的加載流程是非常重的一套流程,即使同一個頁面多次重復訪問,也需要走比較完整的流程,耗時極長,這與用戶的期望是不符的,通常用戶期望訪問過的頁面就能快速展現出來。在一些特定的場景,H5也是可以做到極速展現的,比如,前進后退。其它的場景,比如頁內幾個TAB切換,是否也可以用上這類緩存呢?也是可以的。原理上也是比較簡單的,在頁面首次訪問時,會將排版渲染好的頁面放進WebViewCache里,WebViewCache是存儲完整頁面的一塊內存。
用戶再次訪問該頁面時,會將WebViewCache內存中的完整頁面讀取出來,直接繪制展現,而無需再進行加載解析排版渲染等流程,從而達到極速打開的效果。
除了內核提供WebViewCache基礎技術之外,前端也需要與內核進行一定的交互,比如,通過JSAPI查詢當前頁面是否在WebViewCache,如果在則返回它在WebViewCache列表的位置,然后前端就可以使用JSAPI去跳轉到相應位置的頁面,內核就把頁面從內存讀取和展現出來。使用此類技術,頁面一般能在500ms左右完全展現出來,具有非常好的用戶體驗。
當然這個也是需要瀏覽器內核提供這種能力,如果公司有自己的內核開發團隊,可以做到定制。
(4)前端使用LocalStorage緩存HTML文檔
當前前端渲染非常流行,頁面大部分的邏輯都會由前端JS去執行,JS執行完才會生成完整的HTML文檔,而JS執行的成本是非常大的,JS執行時間可能占據首屏時間的50%,有些甚至能達到80%。那么,我們有沒有可能將JS執行生成的完整HTML文檔緩存起來呢,下次訪問時直接使用已緩存的頁面,而無需重復執行JS?這也是可以的原理上也不復雜,首次訪問頁面時,JS執行完之后會生成完整的HTML文檔,我們將HTML文檔緩存到LocalStorage里面。
在后續的訪問中,我們優先從LocalStorage里面讀取HTML文檔,解析排版渲染頁面,而無需JS執行去生成頁面,讓頁面展現速度得到極大的提升。
這種方案的關鍵在于前端能夠實現一套DOM-Diff更新的機制,在從LocalStorage讀取HTML頁面的同時,前端還會發起請求去更新HTML文檔,在新的HTML文檔回來之后,會和舊的文檔進行Diff,針對Diff來進行局部更新,這樣能保證頁面得到及時的更新。
(5) service worker
參考使用 Service Workers提升體驗,這里附帶介紹下這個方案,目前service worker 只有在android的webview中可用,ios還不支持。我們通過先注冊一個serviceworker服務,指定哪些資源和數據需要存儲,然后下次請求頁面會自動激活這個service worker,頁面請求時會先從service worker中返回緩存的數據。當然service worker中需要自己處理版本和維護數據更新。
Code coverage,檢測哪些代碼執行到了,哪些沒有。支持Javascript和CSS。
webpagetest:https://webpagetest.org/
Chrome Lighthouse 插件:https://chrome.google.com/web...
本文部分圖片和參考內容來自于網絡,如有侵權,請聯系我刪除
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/117500.html
摘要:所以,關于優化實戰我們主要分為兩部分加載渲染鏈路優化和編程代碼優化。加載渲染鏈路優化從訪問到頁面呈現,整個鏈路可以做優化的思路。資源緩存這一節我們單獨介紹緩存,是的,利用好緩存可以解決很多問題,包括頁面加載和渲染的問題都能得到很好的優化。 優化實戰 本文屬于思否課堂VirtualDOM到AST玩轉前端性能原理解析與代碼實戰課程官方博客:fed123.com 我們已經全面分析總結了評估頁...
摘要:在美團支付的前端技術體系里,通過預渲染提升網頁首幀優化,從而優化了白屏問題,提升用戶體驗,并形成了最佳實踐。我們團隊主要負責美團支付相關的業務,如果網站太慢會影響用戶的支付體驗,會造成客訴或資損。 前言 自JavaScript誕生以來,前端技術發展非常迅速。移動端白屏優化是前端界面體驗的一個重要優化方向,Web 前端誕生了 SSR 、CSR、預渲染等技術。在美團支付的前端技術體系里,通...
摘要:發布是由團隊開源的,操作接口庫,已成為事實上的瀏覽器操作標準。本周正式發布,為我們帶來了,,支持自定義頭部與腳部,支持增強,兼容原生協議等特性變化。新特性介紹日前發布了大版本更新,引入了一系列的新特性與提升,本文即是對這些變化進行深入解讀。 showImg(https://segmentfault.com/img/remote/1460000012940044); 前端每周清單專注前端...
摘要:前言通過相關的,我們可以對頁面進行性能分析。下面會就幾個比較重要的過程進行分析,給出耗時計算方法,并針對性的給出一些優化建議。下文中的均表示解析域名系統英文,縮寫是互聯網的一項服務。 前言 showImg(https://segmentfault.com/img/remote/1460000011826826?w=640&h=389); 通過HTML5 Performanc相關的API...
閱讀 2260·2023-04-25 14:50
閱讀 1232·2021-10-13 09:50
閱讀 1866·2019-08-30 15:56
閱讀 1838·2019-08-29 15:29
閱讀 2886·2019-08-29 15:27
閱讀 3547·2019-08-29 15:14
閱讀 1192·2019-08-29 13:01
閱讀 3298·2019-08-26 14:06