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