前端性能優化方案
前端資源比較龐大,包括HTML
、CSS
、JavaScript
、Image
、Flash
、Media
、Font
、Doc
等等,前端優化相對比較復雜,對於各種資源的優化都有不同的方式,按粒度大致可以分為兩類,第一類是頁面級別的優化,例如減小HTTP
請求數、腳本的無阻塞加載、內聯腳本的位置優化等,第二類則是代碼級別的優化,例如JavaScript
中的DOM
操作優化、圖片優化以及HTML
結構優化等等。在用戶角度前端優化可以讓頁面加載得更快,對用戶的操作響應得更及時,能夠給用戶提供更為友好的體驗,在服務商角度前端優化能夠減少頁面請求數,減小請求所占帶寬,能夠節省服務器資源。
減少HTTP請求
加載前端的大部分時間在於下載各種資源,瀏覽器對於同一個服務器的HTTP
請求連接池數量也是有限的,對於過多的請求需要排隊等候,最小化HTTP
請求減少請求次數可以防止HTTP
連接池被占滿,同時也能避免過多HTTP
鏈接時的TCP
握手造成的時間消耗。
CSS Sprite
CSS Sprite
也就是俗稱的雪碧圖,將多張圖片合並到一張圖片中,可以減少圖片的數量,此外由於合並圖片相對分開的圖片減少了存儲信息的開銷如顏色表和格式信息等,合並圖片后的大小比分開的圖片的大小的總和要趨於更小,當然如果合並圖片時有大量空白來分隔原來的單個圖片那么其大小會趨於更大。使用雪碧圖,需要使用CSS
的background-image
和background-position
屬性顯示所需的圖像段。
Image maps
假如網站有很多帶鏈接的圖片例如地圖應用等,那么圖片映射image maps
將是一個很好的選擇,image maps
允許在單張圖片上有很多帶鏈接的圖片,通過<map>
與<area>
來將一張完整的圖片映射分割為多個區域來制作不同的鏈接,同樣是可以減少圖片的HTTP
請求鏈接數量。
Inline images
通過使用data:URL
方案來直接將圖像數據嵌入到頁面或者CSS
中,雖然這會增加文檔或者是CSS
文件的大小,但同樣這確實是一個減少HTTP
請求數量的方案,對於data:URL
的格式為data:[<mediatype>][;base64],<data>
。
Font icon
使用字體圖標來代替圖標,將多個圖標合成為字體圖標不僅可以減少對於圖片的HTTP
請求數量與圖標大小,還作為矢量圖對於放大縮小等操作不會失真,此外字體圖標的優點還包括其很容易改變顏色、產生陰影、透明效果等,可以得到CSS
的很好的支持從而制作各種樣式、旋轉和動畫效果等。
Combined files
Combined files
也就是合並文件,將多個CSS
文件或者JavaScript
文件合並成一個CSS
文件或者JavaScript
文件,可以有效減少HTTP
請求數量,並且可以通過壓縮算法減小文件的大小。當腳本和樣式表在頁面之間變化時,組合文件可能會變得難以閱讀和修改,但是將其作為發布過程的一部分可以縮短響應時間。
利用緩存機制
緩存控制
通過服務器端設置響應頭的Expires
與Cache-Control
來設置資源組件過期時間以及過期策略,對於靜態資源可以通過設置Expires
為一個長期時間來實現永不過期策略,對於動態組件通過Cache-Control
指定緩存機制來輔助瀏覽器處理條件請求。
外部引用
將JavaScript
與CSS
設置為外部文件引入而不是直接嵌入到HTML
中,由於瀏覽器的緩存機制,外部文件可以通過瀏覽器的緩存引入而不需要每次請求重復請求同一個資源文件,這樣就使得瀏覽器在第二次打開頁面的速度會快得多,當然全部由外部文件引入的方式會增加HTTP
請求數量,所以外部引用的關鍵問題就在於如何權衡相對於HTML
文檔數量而言,緩存外部JavaScript
與CSS
文件的數量,盡管難以量化,但可以使用各種度量標准來衡量此因素,網站上的用戶每個會話具有多個頁面視圖,並且許多頁面都重復使用相同的腳本和樣式表,則緩存的外部文件會帶來更大的潛在利益。
優化資源加載
樣式表位置
根據瀏覽器渲染的順序,將CSS
在<head>
中引入或者嵌入,相對於將CSS
放到<body>
或者頁面底部來說,可以使頁面渲染速度加快,這對於頁面內容比較豐富的網站或者網絡鏈接較慢時相當重要。假如將樣式表放置於底部,就會導致瀏覽器還未加載樣式表就開始渲染頁面,無法漸進式渲染頁面而直接從無樣式狀態立即跳轉到有樣式狀態,用戶體驗較差;此外有些瀏覽器可能會在CSS
下載完成后才開始渲染頁面,樣式表放在下方會導致頁面渲染推遲。
腳本位置
瀏覽器是可以並發請求的,這一特點使得其能夠更快的加載資源,然而外部引入JavaScript
腳本在加載時卻會阻塞其他資源,例如在腳本加載完成之前,它后面的圖片、樣式以及其他腳本都處於阻塞狀態,直到腳本加載完成后才會開始加載,原因之一是Js
可能會改變頁面或者改變Js
間的依賴關系,例如A.js
中用document.write
改變頁面,B.js
依賴A.js
。因此要嚴格保證順序,不能並行下載。如果將腳本放在比較靠前的位置,則會影響整個頁面的加載速度從而影響用戶體驗。此外當瀏覽器發現Js
腳本時瀏覽器會立即開始解析腳本,並停止解析文檔,因為腳本有可能會改動DOM
與CSS
,繼續解析會浪費資源。解決這些問題的方法有很多例如異步加載腳本等,而最簡單可依賴的方法就是將腳本盡可能的往后挪,減少對並發下載與頁面渲染的影響。
優化代碼方案
避免CSS表達式
CSS
表達式通過expression
方法來接受JavaScript
表達式,是一種動態設置CSS
的強大的方式,但同樣也是非常危險的方式,CSS
表達式的問題在於其會進行頻繁的計算,CSS
計算的頻率要遠遠超出我們的想象,不僅在頁面顯示和縮放時會進行計算,在頁面滾動或者移動鼠標都會重新計算一次,從而影響到頁面的性能。可以通過使用Js
將屬性進行一次算來並賦值給樣式屬性,也就是一次性表達式,如果必須在頁面的整個生命周期中動態設置樣式屬性,則可以使用事件處理程序代替CSS
表達式。如果必須使用CSS
表達式,需要注意它們可能會被計算數千次,並且很可能會影響頁面的性能。
避免重定向
盡量避免使用重定向,當頁面發生了重定向,就會延遲整個HTML
文檔的傳輸。在HTML
文檔到達之前,頁面中不會呈現任何東西,也沒有任何組件會被下載,降低了用戶體驗。如果一定要使用重定向,如http
重定向到https
,要使用301
永久重定向,而不是302
臨時重定向。因為如果使用302
,則每一次訪問http
,都會被重定向到https
的頁面,而永久重定向,在第一次從http
重定向到https
之后就會被瀏覽器記住,每次訪問http
,會直接返回https
的頁面。
最小化操作DOM
JavaScript
操作DOM
無可避免的會觸發瀏覽器的重繪或者回流,由於重繪和回流可能代價比較昂貴,因此最好就是可以減少它的發生次數,為了減少發生次數,我們可以合並多次對DOM
和樣式的修改,然后一次處理掉,或者將樣式事先設計好,動態去改變class
。或者采用離線修改DOM
的方案,使用documentFragment
對象在內存里操作DOM
,在內存中的DOM
修改就是讓元素脫離文檔流,當然是不會觸發重繪的,將對DOM
的所有修改批量完成,想怎么改就怎么改,然后將節點再放入文檔流中,只觸發一次回流。
壓縮資源文件
Gzip
從HTTP / 1.1
開始,客戶端可以通過使用HTTP
請求中的Accept-Encoding: gzip, deflate
來指示對壓縮的支持。如果服務器在請求中看到此標頭,則可以使用客戶端列出的方法之一壓縮響應,服務器通過響應中的Content-Encoding: gzip
通知客戶端采用gzip
壓縮。Gzip
的壓縮率很高,是目前最流行,最有效的壓縮方法,它由GNU
項目開發,並由RFC 1952
標准化。
壓縮外部文件
壓縮JavaScript
和CSS
文件,從代碼中刪除不必要的字符以減小其大小,從而縮短加載時間,當代碼最小化時,所有注釋以及不需要的空白字符都將被刪除,由於減小了下載文件的大小,因此可以提高響應時間性能。
優化網絡請求
CDN
CDN
的全稱是Content Delivery Network
,即內容分發網絡,CDN
是構建在現有網絡基礎之上的智能虛擬網絡,依靠部署在各地的邊緣服務器,通過中心平台的負載均衡、內容分發、調度等功能模塊,使用戶就近獲取所需內容,降低網絡擁塞,提高用戶訪問響應速度和命中率。當用戶處於跨地域的多個位置時,對於服務器響應速度的感知是有差別的,用戶訪問網站的絕大部分時間都是處於下載靜態資源狀態的,將這些靜態資源首先分發到CDN
各服務器,可以大大縮短響應時間,CDN
可以根據用戶網絡狀態信息來選擇網絡跳數最少的服務器或響應最快的服務器來就近交予用戶資源。
DNS預解析
當瀏覽器訪問一個域名的時候,需要解析一次DNS,獲得對應域名的ip
地址。在解析過程中,按照瀏覽器緩存、系統緩存、路由器緩存、ISP
(運營商)DNS
緩存、根域名服務器、頂級域名服務器、主域名服務器的順序,逐步讀取緩存,直到拿到IP
地址,DNS Prefetch
,即DNS
預解析就是根據瀏覽器定義的規則,提前解析之后可能會用到的域名,使解析結果緩存到系統緩存中,縮短DNS
解析時間,來提高網站的訪問速度
<link rel="dns-prefecth" href="https://www.google.com">
<link rel="dns-prefecth" href="https://www.google-analytics.com">
提前解析DNS
,由於它是並行的,不會堵塞頁面渲染,這樣可以縮短資源加載的時間
配置ETag
實體標簽ETag
是Web
服務器和瀏覽器用來確定瀏覽器緩存中的資源是否與原始服務器上的資源匹配的一種機制,添加了ETag
,以提供一種比上次修改日期更靈活的驗證實體的機制。ETag
是唯一標識組件特定版本的字符串,唯一的格式限制是用引號引起來,原始服務器使用ETag
響應頭指定組件的ETag
。
盡早釋放緩沖
當用戶請求頁面時,后端服務器將HTML
頁面拼接在一起可能需要200
到500
毫秒的時間,在這段時間內,瀏覽器在等待數據到達時處於空閑狀態,這段時間則可以將服務端部分已經處理好的數據發送到前端,使瀏覽器先開始加載外部資源。例如使用PHP
,則可以使用函數flush()
將部分就緒的HTML
響應發送到瀏覽器,以便瀏覽器可以在后端忙於處理HTML
頁面的其余部分時開始獲取資源,好處主要體現在繁忙的后端或輕量級前端。
每日一題
https://github.com/WindrunnerMax/EveryDay
參考
https://www.jianshu.com/p/fbd1d510be67
https://www.cnblogs.com/coober/p/8078847.html
https://www.cnblogs.com/psxiao/p/11552823.html
https://www.cnblogs.com/xiaohuochai/p/9178390.html
https://developer.yahoo.com/performance/rules.html