摘要:本文主要介紹關鍵渲染路徑與網絡兩個方面的性能優化并提供,篇幅較長建議電腦觀看。百度統計代碼注意,的腳本不會被阻塞,完成后立即執行,但是有可能會阻塞關鍵渲染路徑。
本文主要介紹“關鍵渲染路徑”與“網絡”兩個方面的性能優化并提供demo,篇幅較長建議電腦觀看。
前端優化的方面太多,本文介紹的僅僅是其中的一部分,力求涵蓋“關鍵渲染路徑”的方方面面,及一些不常被提到的“網絡優化”部分。
測試環境如無特殊說明均為Chrome 57
瀏覽器從打開一個URL到渲染完頁面共有:
下載HTML文檔
下載HTML文檔中的css
下載Js文件
執行js腳本
下載其他資源
通過HTML文檔構建DOM(Parse HTML)
通過CSS文件構建CSSOM(Parse CSS)
通過DOM與CSSOM計算render tree
根據render tree進行繪制,計算各個元素位置與大小(Layout)
對頁面進行上色,渲染為最終顯示的像素(Paint)
第一次完成Paint稱為“初次渲染”,這時候用戶就能看到render tree里面的東西了。而完成初次渲染的過程稱為“關鍵渲染路徑”,關鍵渲染路徑上需要加載的資源叫做“關鍵資源”
這個過程很多很復雜,其中的依賴關系也很復雜,筆者嘗試畫圖來表示,但是實在是沒畫出來,所以還是用文字來表述吧:
引入的資源,哪怕被阻塞(比如被js腳本阻塞后續link標簽),瀏覽器依舊會智能的預先加載它們(但是不執行)
“CSS文件的加載”會阻塞“Js文件執行”。若CSS引用在Js文件之前,“加載CSS文件”會阻塞“Js文件執行”。即CSS文件未加載解析完成前,js文件不會得到執行。因為js有可能會修改CSSOM。帶有async和defer屬性的script不受限制。
Parse HTML的解析是增量的,因此瀏覽器可以邊下載HTML邊構建DOM樹
“CSS文件的加載”會阻塞“Layout”。若頁面有正在加載的CSS文件,在CSS文件加載完之前,瀏覽器不會對頁面進行Layout,這是為了防止樣式突變帶來的抖動
“加載Js文件”會阻塞“Parse HTML”,這個估計大家都知道了,因為js可以通過document.write修改HTML文檔流
“Js文件執行”會幾乎會阻塞所有東西,包括Layout
比較有意思的是,字體的加載會阻塞局部的渲染。若某一段文本的字體使用了一個尚未加載完的字體,這段文本則先不會被Paint,直到字體加載完或者超過某個時間(通常是3秒)文本才會突然顯示。
瀏覽器為了避免FOUT(Flash Of Unstyled Text),會盡量等待字體加載完成后,再顯示應用了該字體的內容。只有當字體超過一段時間仍未加載成功時,瀏覽器才會降級使用系統字體。每個瀏覽器都規定了自己的超時時間(Chrome是3秒)。但這也帶來了FOIT(Flash Of Invisible Text)問題。內容無法盡快地被展示,導致空白
一些Demo來解釋瀏覽器渲染流程CSS會阻塞Layout:Demo
Title Hello
World
CSS會阻塞Js執行:Demo
Title Hello
World
Js執行會阻塞關鍵渲染路徑,哪怕是defer還是async:Demo
Title Hello
World
Foot會阻塞局部渲染,但是智能的瀏覽器會給他設定一個上限,一般是3秒鐘:Demo
CSS篇優化策略Title Hello
World
優化核心概念是:將初次渲染不需要的CSS想辦法剝離出關鍵渲染路徑
如果僅僅是為了提前初次渲染時間而進行優化,將頁面必備的CSS剝離關鍵渲染路徑而造成樣式突變導致頁面抖動,則得不償失了
使用link/style的media屬性對某些媒體查詢條件觸發后才使用的css,可以在link標簽中加入media屬性,如下:
此樣式表仍會加載。當瀏覽器環境不匹配媒體查詢條件時,該樣式表不會阻塞渲染。我們可針對不同媒體環境拆分CSS文件,并為link標簽添加媒體查詢,避免為了加載非關鍵CSS資源,而阻塞初次渲染
使用DOM API添加CSS可以使用js代碼來添加css
var style = document.createElement("link"); style.rel = "stylesheet"; style.href = "index.css"; document.head.appendChild(style);使用resoure hint規范的preload
將link標簽的rel屬性設置為preload,瀏覽器遇到遇到標記為preload的link時,會開始加載它,但是由于rel不是stylesheet,因此不會阻塞渲染。
然后在適當的時候,在rel改為stylesheet,即可應用此樣式。
但是這個屬性兼容性比較差,詳細可以參考這里。不過有一個polyfill可以用loadCSS,原理是通過DOM API插入樣式資源。
這個屬性的使用情景有些偏,也可能是我理解問題:
當使用preload引入css文件時,實際上證明這個頁面根本不需要這個css,它有可能是打印樣式,或者是響應式網站的另一套css代碼。但是,使用preload屬性,瀏覽器反而會預先加載它,也就是說,在window.onload之前,用戶將耗費了網絡資源在加載一個暫時不需要的樣式。網絡資源不可能是無限的,也就是說這個css會占用頁面其他資源比如圖片的網絡資源。
詢問瓜瓜老師本人后,瓜瓜老師說:
舉個例子。第三屏有個廣告版,它的樣式
這樣確實這個css的緊急程度就介于關鍵渲染路徑的css與頁面圖片之間了,不過貌似這個情景很受限。
JS篇優化策略 使用defer延遲腳本執行當script標簽擁有defer屬性時,該腳本會被推遲到整個HTML文檔解析完后,再開始執行。因此將腳本放在head中,可以提早瀏覽器對腳本文件的加載,但是卻不會阻塞parse HTML。
注意,defer的腳本不會被css阻塞,parse HTML完成后立即執行,但是有可能會阻塞關鍵渲染路徑。為什么說有可能呢,假如腳本文件在render tree生成前加載完畢,則會開始執行,執行過程中會阻塞關鍵渲染路徑。請參考這個Demo
被defer的腳本,在執行時會嚴格按照在HTML文檔中出現的順序執行,但是實際上貌似不是這樣,js文件前后文件若有依賴需慎重使用。
使用async延遲腳本執行和defer類似,只是當js加載完后馬上執行,而不在乎parse HTML是否完成,因此假如腳本比css先加載完,也會阻塞關鍵渲染路徑。
使用DOM API
據筆者所知,這是唯一一種100%不會阻塞關鍵渲染路徑的js腳本加載方式。通過DOM API引入的js腳本會等到頁面Layout和Paint后再開始執行,不論你將載入js文件的代碼放在head中還是body后面亦是如此。
其他的優化 使用Web Font Loader加載字體若不想讓字體阻塞局部渲染,可使用Web Font Loader
網絡優化篇網絡優化和CSS優化策略相同,盡可能讓關鍵資源提前加載完,所以優化時盡量將以下指標壓縮到最低:
關鍵資源數
關鍵資源體積
關鍵資源網絡來回數
當然,如果你的項目使用了先進的SPDY或HTTP/2,下面的方法可能并不適用。
優化關鍵資源數RFC2616規定同域名同時只能有 2 個連接(RFC7230 中無限制),而???????現代瀏覽器一般允許同域6個并發連接。因此,當頁面中有許多需要外鏈的資源(script、link等),瀏覽器最多在每個域同時并發下載6個。
每一個請求,若使用域名,則需要額外增加一次DNS查詢時間(若緩存未過期會命中緩存),因此一個網站過多的使用不同域名的資源會額外增加DNS查詢開銷,這點在移動端非常明顯。
當然,每個請求建立根據TCP協議規定,還需要先進行3次捂手才可以建立鏈接。
合并請求盡可能的合并請求,減少網絡請求數。這一點可能在其他性能優化文章都說爛了:
小圖片轉base64
合并打包CSS、JS文件
現在的比較流行的webpack就非常擅長做這種事情
適度使用內聯CSS和Js使用內聯的CSS和JS固然可以減少請求,但是使用內聯也意味著你的CSS和JS將不會再被瀏覽器緩存,因此要適度的使用內聯,內聯不是萬能的。
從HTTP協議下手最佳方案肯定是過渡到HTTP/2無疑,但是現在HTTP/2的支持并不算太好,而且各大瀏覽器僅支持TLS下實現的HTTP/2(說白了就是HTTPS),使得HTTP/2的使用存在許些限制。
如果沒有HTTP/2,或許可以:
使用Keep-Alive可以規避TCP三次握手的時間
使用Transfer-Encoding:chunked分塊輸出文件,還記得parse HTML的過程是增量的嗎?若瀏覽器可以邊下載HTML文件邊解析,豈不美哉?
減少重定向,這個看上去理所當然但是實際上卻很容易被忽略
適度使用域名散列瀏覽器同域并行下載數量有限,所以只要多建立幾個二級域名就好了,然后合理的分配各個資源就好了。
假如由于某些不可抗拒原因,關鍵資源數是12個,那么只要建立2個二級域名分別分配給其中的12個資源,瀏覽器會同時并行下載它們了。
不過,使用域名散列要適度,每一個域名都需要額外的增加一次DNS查詢時間。當然,DNS本身也有緩存,或許適當的增加DNS TTL時間也是個不錯的主意。
壓縮關鍵資源體積對于js、css文件,現在網上現成的壓縮工具一堆,而且應用十分廣泛,相信大家都知道了,這里就不多說了。
說到壓縮,服務器開啟一定的壓縮策略(如gzip)是個不錯的主意,效果拔群,資源大概會壓縮到原有的1/3左右。
圖片壓縮,這個需要知道什么情境下適合什么類型的圖片,GIF、JPG、PNG使用情景各不相同,具體可以參考這篇文章:圖片格式那么多,哪種更適合你?
關鍵資源網絡來回數假如一個頁面需要引入2個CSS才能工作,下面有2種方式
2個均用link引入
1個用link引入,在css中import另一個css
毫無疑問肯定是前者快,因為前者的網絡來回數是1,而后者是2。
因此,盡可能將資源加載扁平化,減少關鍵資源網絡來回數是個不錯的主意。
當然,優化時要注意的點也有不少,比如前面提到的瀏覽器同域并發限制等,需要權衡使其不要影響到其他的導致初次渲染時間延后。
一些無效的優化策略使用document.write打印link標簽引入css仍會阻塞初次渲染。
引用奇舞團@瓜瓜老師:
PPT:https://ppt.baomitu.com/d/258...
個人主頁:http://melonh.com/
奇舞團@屈屈老師:
PPT:https://ppt.baomitu.com/d/a8a...
個人主頁:https://imququ.com/
W3C規范:
https://www.w3.org/TR/2016/RE...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/50727.html
摘要:前端性能優化的涉及點從服務器到協議再到宿主環境本身都要有比較深刻的認識,業界目前主要還是以雅虎總結出來條前端性能優化的黃金軍規為參考。 歡迎大家前往騰訊云技術社區,獲取更多騰訊海量技術實踐干貨哦~ 導語 : 從事前端有6年+的時間了,從最開始的美工到重構再到偏向js邏輯開發的前端開發,一直在前端這個行業里面摸索和學習,我現在將自己這些年的一個心得體會來個系統性的梳理寫成一篇關于性能優化...
摘要:前言對于前端的性能話題,從來都沒有斷絕過。作為一個前端開發者,性能是我們關注的指標。前端發展以來,優化方式,琳瑯滿目,有雅虎軍規等。所以,接下來我會從三個方面就前端性能進行總結網絡方面操作及渲染方面數據方面。 前言 對于前端的性能話題,從來都沒有斷絕過。因為這個東西沒有最好,只有更好。而且往往也是業務的繁雜程度去決定優化程度的。作為一個前端開發者,性能是我們關注的指標。它直接影響著我們...
摘要:前言對于前端的性能話題,從來都沒有斷絕過。作為一個前端開發者,性能是我們關注的指標。前端發展以來,優化方式,琳瑯滿目,有雅虎軍規等。所以,接下來我會從三個方面就前端性能進行總結網絡方面操作及渲染方面數據方面。 前言 對于前端的性能話題,從來都沒有斷絕過。因為這個東西沒有最好,只有更好。而且往往也是業務的繁雜程度去決定優化程度的。作為一個前端開發者,性能是我們關注的指標。它直接影響著我們...
摘要:前言對于前端的性能話題,從來都沒有斷絕過。作為一個前端開發者,性能是我們關注的指標。前端發展以來,優化方式,琳瑯滿目,有雅虎軍規等。所以,接下來我會從三個方面就前端性能進行總結網絡方面操作及渲染方面數據方面。 前言 對于前端的性能話題,從來都沒有斷絕過。因為這個東西沒有最好,只有更好。而且往往也是業務的繁雜程度去決定優化程度的。作為一個前端開發者,性能是我們關注的指標。它直接影響著我們...
閱讀 4675·2021-09-22 16:06
閱讀 2074·2021-09-22 15:22
閱讀 1410·2019-08-30 15:54
閱讀 2511·2019-08-30 15:44
閱讀 2341·2019-08-29 16:31
閱讀 2010·2019-08-29 16:26
閱讀 2328·2019-08-29 12:41
閱讀 730·2019-08-29 12:22