高效能網站建設指南-前端效能優化(一)
年前,讀完了《高效能網站建設指南》,但是一直沒有整理。年後回來和同事一起出了份前端面試題,涉及到了關於效能優化的問題,在此特梳理一下。
大量的公司在開發功能業務時,只關注功能點的實現,對於效能方面要求很低甚至不作為考慮範圍。在遇到一些效能瓶頸時,也往往通過加機器的暴力方式去減緩,但那並不是解決問題的根本。作為前端工程師,大部分人為了迎合需求一直在學習JavaScript、CSS、HTML5及Node,很少去關注效能方面的東西。然而,有些效能的優化點只需要花費很少的時間和精力就能換來巨大的改善使用者體驗。在陳述前端效能優化的問題之前,我們先思考如下問題:
一個頁面從輸入 URL 到頁面載入顯示完成,這個過程中都發生了什麼?
- 在瀏覽器輸入地址;
- 瀏覽器查詢域名的
IP
地址,包括DNS
具體的查詢過程,包括:瀏覽器快取、系統快取、路由器快取等; - 瀏覽器向
web
伺服器傳送一個HTTP
請求; - 伺服器的永久重定向響應(從
http://example.com
到http://www.example.com
); - 瀏覽器跟蹤重定向地址;
- 伺服器處理請求;
- 伺服器返回一個
HTTP
響應; - 瀏覽器渲染顯示
HTML
; - 瀏覽器傳送請求獲取嵌入在
HTML
中的資源(如圖片、音訊、視訊、CSS
、JS
等等); - 瀏覽器傳送非同步請求。
效能黃金法則:只有10%-20%的終端使用者響應時間花在了下載HTML文件上。其餘的80%-90%時間花在了下載頁面中的所有元件上。
寫在前面
在闡述優化點之前,有必要的先說明一下HTTP,其作為瀏覽器和伺服器之間的一種傳輸協議,在整個過程中的作用至關重要!對HTTP更多的瞭解,推薦閱讀《HTTP權威指南》。
壓縮
壓縮響應是最卓有成效的優化方式,瀏覽器可以使用Accept-Encoding頭來宣告支援壓;伺服器使用Content-Encoding頭確認響應已被壓縮。
==Request Headers==
Accept-Encoding:gzip
==Response Headers==
Content-Encoding:gzip
條件GET請求
如果瀏覽器在其快取中保留了元件的一個副本,但並不確定它是否仍然有效,就會生成一個條件Get請求。如果確認快取在副本仍然有效,瀏覽器就可以使用快取中的副本。
典型情況下,快取副本的有效性源自其最後修改時間。基於響應中的Last-Modified頭,瀏覽器可以知道元件最後的修改時間。它會使用If-Modified-Since頭將最後修改時間傳送給伺服器。如果元件沒有被修改過,伺服器會返回一個“304 Not Modified”狀態碼並不再發送響應體,從而得到一個更小且更快的相應。在HTTP1.1中可以使用ETag和If-None-Match進行條件GET請求(下面講述)。
==Request Headers==
If-Modified-Since:Thu, 07 Apr 2016 08:30:15 GMT
==Response Headers==
Last-Modified:Thu, 07 Apr 2016 08:30:15 GMT
Expires
條件GET請求和304響應有助於讓頁面載入得更快,但仍需要在客戶端和伺服器之間進行一次往返確認,以執行有效性檢查。Expires頭明確指出瀏覽器是否可以使用元件的快取副本。如果元件沒有過期,瀏覽器就會使用快取版本而不會進行任何HTTP請求。
==Response Headers==
Expires:Thu, 07 Apr 2019 08:30:15 GMT
Keep-Alive
HTTP構建在傳輸控制協議TCP(Transmission Control Protocol)之上。HTTP早期實現中,每個HTTP請求都要開啟一個socket連線。持久連線可以確保在單獨的連線上進行多個請求。瀏覽器和伺服器使用Connection頭來指明對Keep-Alive的支援。在HTTP1.1中並不是必須的,HTTP1.1中定義的管道可以在一個單獨的socket上傳送多個請求,管道效能優於持久連線。但IE7不支援,所以很多瀏覽器和伺服器仍然包含Keep-Alive。
==Request Headers==
Connection:keep-alive
==Response Headers==
Connection:keep-alive
規則1:減少HTTP請求
效能黃金法則中提到80%~90%時間花在HTML文件中元件下載。因此,減少元件的數量,並由此減少HTTP請求的數量。是改善響應時間的最簡單途徑。
圖片地圖
對於“圖片超連結”的情況,可以使用圖片地圖減少頁面圖片個數,從而減少HTTP請求。其分為伺服器端圖片地圖和客戶端圖片地圖,詳見:HTML5-嵌入內容
CSS Sprites
同圖片地圖,CSS Sprites也可合併圖片,將多個圖片合併到一個單獨的圖片中,使用CSS的background-position屬性將HTML元素放到背景圖片中期望的位置上。
<div style="background-image: url('sprites.git');
background-position: -260px -90px;
width: 26px; height: 26px;">
</div>
注意:圖片地圖中的圖片必須是連續的,而CSS Sprites則沒有這個限制。
內斂圖片
通過使用data: [<mediatype>][;base64],<data>
模式可以在Web頁面中包含圖片,而無需額外的HTTP請求(IE不支援)。要注意,在跨頁面時不會被快取。不要去內聯公司的logo,因為編碼過的logo會導致頁面變大。聰明的做法是:使用CSS將內聯圖片作為背景,將其放在外部樣式表中,資料可以快取在樣式表內部。雖然將內聯圖片放置在外部樣式表中增加了一個額外的HTTP請求(請求樣式表),但被快取後可以得到額外的收穫。當然,對於只使用一次(如,驗證碼)直接可以寫在頁面上。
示例:存放到樣式表
.cart {background-img: url(data:image/png;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDA...)}
示例:直接頁面嵌入
<img src="data:image/png;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDA..." />
合併指令碼和樣式表
合併指令碼和樣式表,是最普通不過的效能優化方式,可以使用Grunt、Webpack、Gulp等工具,這裡不再贅述。需要思考的是:一個多頁面的網站會有大量的模組,而模組的組合情況複雜,如何合併模組值得花時間去分析一下自己的頁面,確保組合的數量是可管理的。
規則2:使用內容釋出網路
內容釋出網路(CDN)是一組分佈在多個不同地理位置的Web伺服器,用於更加有效地向用戶釋出內容,其目的是使使用者可就近取得所需內容,解決 Internet網路擁擠的狀況,提高使用者訪問網站的響應速度。使用CDN,需要注意:更新內容後,CDN的生效時間!
規則3:新增Expires頭
Expires頭在前面已經闡述過,其目的主要是最大化利用瀏覽器的快取來改善頁面的效能。
Expires頭
瀏覽器(和代理)使用快取來減少HTTP請求的數量,並減少HTTP響應的大小。
==Response Headers==
Expires:Thu, 07 Apr 2019 08:30:15 GMT
其告訴瀏覽器可以使用該元件的快取,直到2019年4月7日上午8時30分15秒。
Max-Age和mod_expires
HTTP1.1中引入了Cache-Control
來克服Expires
頭的限制。Expires
頭使用一個特定的時間,它要求伺服器和客戶端的時間嚴格同步(當然,可以通過Apache mode_expires模組中的ExpiresDefault以相對方式設定日期);另外,過期日期需要經常檢查,一旦到達過去日期還需要在伺服器端配置中提供一個新的日期。
Cache-Control: max-age=秒數
指定元件快取多久(下述,快取1年)。
==Response Headers==
Cache-Control: max-age=31536000
max-age
可以消除Expires的限制,但對於不支援HTTP1.1的瀏覽器,可以同時設定二者。二者同時存在時,HTTP規定max-age指令將重寫Expires頭。
修訂檔名
如果我們將元件配置可以在瀏覽器端進行快取,當這些元件改變時使用者如何獲得更新呢?設定了Expires頭時,過期前會一直使用快取版本(從硬碟上讀取元件),瀏覽器不會更新。為了確保使用者能夠獲取元件的最新版本,需要在所有HTML頁面修改元件的檔名。常用方式是增加MD5戳。
規則4:配置ETag
實體標籤(Entity Tag,ETag)是Web伺服器和瀏覽器用於確認快取元件有效性的一種機制。
瀏覽器下載元件後,會進行快取,再次使用該元件時,會根據Expires頭的值,判斷是否發起請求。如果過期了,瀏覽器在重用之前必須檢查他是否仍然有效,傳送條件GET請求(前面已經提及)。如果是有效的,伺服器會返回“304 Not Modified”,不會返回整個元件;這比簡單地下載所有過期的元件效率要高。
伺服器在檢測快取元件是否和原始伺服器上的元件匹配時有兩種方式:
- 比較最新修改日期 (If-Modified-Since ==> Last-Modified)
- 比較實體標籤 ()
最新修改日期
原始伺服器通過Last-Modified響應頭來返回元件最新修改日期。
==Request Headers==
GET /1/4/A/1_ligang2585116.jpg
Host: avatar.csdn.net
==Response Headers==
HTTP 1.1 200 OK
Last-Modified: Wed, 11 Nov 2015 20:24:15 GMT
Content-Length: 19613
下一次請求http://avatar.csdn.net/1/4/A/1_ligang2585116.jpg時,瀏覽器會使用If-Modified-Since頭將最新修改日期傳回到原始伺服器以進行比較。如果伺服器上元件的最新修改日期與瀏覽器傳回的值匹配,返回304,不會傳送19613位元組的資料。
==Request Headers==
GET /1/4/A/1_ligang2585116.jpg
Host: avatar.csdn.net
If-Modified-Since: Wed, 11 Nov 2015 20:24:15 GMT
==Response Headers==
HTTP 1.1 304 Not Modified
比較實體標籤
ETag在HTTP1.1中引入,ETag是唯一標識了一個元件的一個特定版本的字串。
==Request Headers==
GET /1/4/A/1_ligang2585116.jpg
Host: avatar.csdn.net
==Response Headers==
HTTP 1.1 200 OK
Last-Modified: Wed, 11 Nov 2015 20:24:15 GMT
ETag: "8224274EB79860E83F60346E0EEBE99A"
Content-Length: 19613
ETag的加入為驗證實體提供了比較新修改日期更靈活的機制。例如,如果實體依據User-Agent或Accept-Language頭而改變,實體的狀態可以反映在ETag中。瀏覽器會使用If-None-Match頭將ETag傳回原始伺服器以進行比較。如果伺服器上元件的ETag值與瀏覽器傳回的值匹配,返回304,不會傳送19613位元組的資料。
==Request Headers==
GET /1/4/A/1_ligang2585116.jpg
Host: avatar.csdn.net
If-Modified-Since: Wed, 11 Nov 2015 20:24:15 GMT
If-None-Match: "8224274EB79860E83F60346E0EEBE99A"
==Response Headers==
HTTP 1.1 304 Not Modified
ETag帶來的問題
ETag通常使用元件的某些屬性構造而成,這些屬性對應特定的、寄宿了網站伺服器來說是唯一的。當瀏覽器從一臺伺服器上獲取了原始元件,之後,又向另外一臺不同的伺服器傳送提交GET請求,ETag是不會匹配的–這對於伺服器叢集來處理請求的網站很常見,大大降低有效驗證的成功率。
If-None-Match比If-Modified-Since具有更高的優先順序。你可能希望如果ETag不匹配但最新修改時間相同,也能傳送一個“304 Not Modified”響應,但實際並不是這樣的。HTTP1.1規範https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3.4,如果請求中同時出現了這兩個頭,則原始伺服器“禁止(MUST NOT)”返回304,除非請求中的條件頭欄位全部一致。
ETag—用還是不用
上面描述了ETag對於叢集式網站的嚴重問題。但你可能會說,利用長久Expires頭,使元件更長時間快取到客戶端,但是一旦使用者點選了Reload或Refresh按鈕,依然會產生條件GET請求。所以,你可以定義ETag只保留大小和時間戳作為內容,或者直接移除ETag。
相關推薦
高效能網站建設指南-前端效能優化(一)
年前,讀完了《高效能網站建設指南》,但是一直沒有整理。年後回來和同事一起出了份前端面試題,涉及到了關於效能優化的問題,在此特梳理一下。 大量的公司在開發功能業務時,只關注功能點的實現,對於效能方面要求很低甚至不作為考慮範圍。在遇到一些效能瓶
淺談前端效能優化(一)
前端效能優化中,減少HTTP請求可以提高頁面的響應速度。 瀏覽器在第一次訪問頁面時向伺服器請求資源,並快取起來,下次再訪問時會判斷在快取中是否已有該資源且有沒有更新過,如果已有該資源且未更新過,則直接從瀏覽器快取中讀取。原理:通過HTTP 請求頭中的 If-Modified-Since(If-No-Matc
Web前端效能優化(一)
1. 靜態資源的壓縮與合併 我們在開發的時候會習慣縮排和寫註釋,方便我們在日常的維護,但將程式碼上傳至服務端後,我們完全可以把那些空格、製表符、換行符進行壓縮,以此減少請求資源的大小;同樣的,我們在服務端所引用的第三方庫進行合併,能減少 HTTP 的請求數量 將
前端效能優化(一)-- 檔案的壓縮與合併
首先我們需要搞清楚,我們為什麼需要進行檔案的壓縮與合併?壓縮與合併的原因主要有兩點 減少HTTP請求數 減小HTTP的請求大小 這裡的主要優化方式有3點: HTML/CSS/JS檔案的壓縮 CSS/JS檔案的合併 開啟GZIP壓縮 如何進行HTML壓縮 使用線上網站壓縮
淺談前端效能優化(二)——對HTTP傳輸進行壓縮
1、前端效能優化的一點: 對js、css、圖片等進行壓縮,儘可能減小檔案的大小,減少檔案下載的時間,從而減少網頁響應的時間。 2、前端效能優化的另一點: 對HTTP傳輸進行壓縮,即在js,css、圖片等資源已經壓縮的基礎上(其實,檔案的壓縮與否均可,檔案的壓縮跟HTTP傳輸過程的壓縮沒關
Web前端效能優化(三)新增Expires頭
什麼是Expires頭? Expires儲存的是一個用來控制快取失效的日期。當瀏覽器看到響應中有一個Expires頭時,它會和相應的元件一起儲存到其快取中,只要元件沒有過期,瀏覽器就會使用快取版本而不會進行任何的HTTP請求。Expires設定的日期格式必須為GMT
Web前端效能優化(六)減少DNS查詢、避免重定向
一、減少DNS查詢 基礎知識 DNS(Domain Name System): 負責將域名URL轉化為伺服器主機IP。 DNS查詢流程:首先檢視瀏覽器快取是否存在,不存在則訪問本機DNS快取,再不存在則訪問本地DNS伺服器。所以DNS也是開銷,通常瀏覽器查詢一個
oracle程式設計300例-效能優化(一)
1、在SELECT語句中避免使用“*” 2、儘可能減小記錄行數 3、使用rowid高效刪除重複記錄 例項: delete from stu s where s.rowid>(select min(t.rowid) from stu t where t.stu=t.stu / 4、使用t
MySQL之查詢效能優化(一)
為什麼查詢速度會慢 通常來說,查詢的生命週期大致可以按照順序來看:從客戶端,到伺服器,然後在伺服器上進行解析,生成執行計劃,執行,並返回結果給客戶端。其中“執行”可以認為是整個生命週期中最重要的階段,這其中包括了大量為了檢索資料到儲存引擎的呼叫以及呼叫後的資料處理,包括排序、分組等。 在完成這些任務的時候
JVM效能優化(一)JVM技術入門
作者 Eva Andreasson 譯者:趙峰 校對:方騰飛 原文連結 Java應用程式是執行在JVM上的,但是你對JVM技術瞭解嗎?這篇文章(這個系列的第一部分)講述了經典Java虛擬機器是怎麼樣工作的,例如:Java一次編寫的利弊,跨平臺引擎,垃圾回收基礎知識,經典的GC演算法和編譯優
百萬級資料庫效能優化(一)——建立索引
對查詢進行優化,要儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。 為了能夠使用索引,我們應該避免使用以下查詢方式: 2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表
UI效能優化(一)Overdraw排查和調優
文章目錄 概述與案例 排查技巧一:檢視是否過度繪製 排查技巧二:通過Hierachy View或者Layout Inspecot檢視佈局層級 Overdraw優化策略-扁平化 一、至尊超薄
資料庫效能優化(一) 索引
當前主流關係型資料庫RDBMS都是將平衡樹(B樹、B+樹)作為預設索引的資料結構。主鍵與索引A. 表不加主鍵,會以無序的形式一行一行的存放在磁碟上。B. 表增加主鍵後,轉變為樹狀結構,整個表變成一個聚集索引。索引的優缺點優點:索引可提升表的查詢速度;為用來排序或分組的欄位新增
Android效能優化(一)App啟動原理分析及啟動時間優化
一、啟動原理解析 Android是基於Linux核心的,當手機啟動,載入完Linux核心後,會由Linux系統的init祖先程序fork出Zygote程序,所有的Android應用程式程序以及系統服務程序都是這個Zygote的子程序(由它fork出來的)。其中最重要的一個就
HTTP/2 與 WEB 效能優化(一)
提醒:本文最後更新於 1333 天前,文中所描述的資訊可能已發生改變,請謹慎使用。 2013 年 11 月份開始,我的部落格開始支援了 SPDY 協議(詳見這裡),也就是 HTTP/2 的前身。今年二月份,Google 宣佈將在 16 年初放棄對 SPDY 的支援,隨後 Google 自家支援
效能優化(一)Hibernate 利用快取(一級、二級、查詢)提高系統性能
在hibernate中我們最常用的有三類快取,分別為一級快取、二級快取和查詢快取,下面我們對這三個快取在專案中的使用以及優缺點分析一下。 快取它的作用在於提高效能系統性能,介於應用系統與資料庫之間而存在於記憶體或磁碟上的資料。 我們程式設
Android效能優化(一)記憶體洩露優化(靜態變數、單例模式、屬性動畫)
記憶體洩露優化分為兩個方面,一方面是在開發過程中避免寫出有記憶體洩露的程式碼,另一方面是通過一些分析工具比如 MAT來找出潛在的記憶體洩露繼而解決。 一、靜態變數導致記憶體洩露。一般情況下靜態變數引用
超詳細:資料庫效能優化(一)
出處: 1.資料庫訪問優化法則 要正確的優化SQL,我們需要快速定位能性的瓶頸點,也就是說快速找到我們SQL主要的開銷在哪裡?而大多數情況效能最慢的裝置會是瓶頸點,如下載時網路速度可能會是瓶頸點,本地複製檔案時硬碟可能會是瓶頸點,為什麼這些一般的工
Webpack 效能優化 (一)(使用別名做重定向)
前言 Webpack 是 OneAPM 前端技術棧中很重要的一部分,它非常好用,如果你還不瞭解它,建議你閱讀這篇 Webpack 入門指迷 ,在 OneAPM 我們用它完成靜態資源打包,ES6 程式碼的轉換 ,React 元件的組織等,在接下來的日子裡,我們將
Storm 使用經驗與效能優化(一)
提交任務:storm jar storm-starter-topologies-1.0.1.jar org.apache.storm.starter.WordCountTopology word-count查詢任務:storm list Kill任務:storm kill