以下是正文。
前言
提升頁面性能優化的常見方式:
-
1、資源壓縮合並,減少http請求
-
2、非核心代碼異步加載 --> 異步加載的方式 --> 異步加載的區別
-
3、利用瀏覽器緩存 --> 緩存的分類 --> 緩存的原理
緩存是所有性能優化的方式中最重要的一步【重要】
有的人可能會回答local storage 和session storage,其實不是這個。瀏覽器緩存和存儲不是一回事。
- 4、使用CDN
瀏覽器第一次打開頁面時,緩存是起不了作用的。這個時候,CDN就上場了。
- 5、DNS預解析
一、資源壓縮合並,減少http請求
-
合並圖片(css sprites)、CSS和JS文件合並、CSS和JS文件壓縮
-
圖片較多的頁面也可以使用 lazyLoad 等技術進行優化。
-
精靈圖等
二、非核心代碼異步加載
異步加載的方式:(這里不說框架,只說原理)
-
動態腳本加載
-
defer
-
async
動態腳本加載
使用document.createElement創建一個script標簽,即document.createElement('script'),然后把這個標簽加載到body上面去。
參考鏈接:
defer
通過異步的方式加載defer1.js文件:
<script src="./defer1.js" defer></script>
async
HTmL5新增特性。
通過異步的方式加載async1.js文件:
<script src="./async1.js" async></script>
defer和async的區別
-
defer:在HTML解析完之后才會執行。如果是多個,則按照加載的順序依次執行。
-
async:在加載完之后立即執行。如果是多個,執行順序和加載順序無關。
代碼舉例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<!--通過異步的方式引入兩個外部的js文件-->
<script src="./defer1.js" defer></script>
<script src="./defer2.js" defer></script>
</head>
<body>
<script>
console.log('同步任務');
</script>
</body>
</html>
上方打印的結果是:
同步任務
defer1
defer2
因為defer的加載是有順序的,所以兩個引入defer文件按順序執行。如果把引入的文件改為async的方式加載,打印的結果可能是:
同步任務
async2
async1
參考鏈接:
三、利用瀏覽器緩存
緩存:資源文件(比如圖片)在本地存有副本,瀏覽器下次請求的時候,可能直接從本地磁盤里讀取,而不會重新請求圖片的url。
緩存分為:
-
強緩存
-
協商緩存
強緩存
強緩存:不用請求服務器,直接使用本地的緩存。
強緩存是利用 http 響應頭中的Expires或Cache-Control實現的。【重要】
瀏覽器第一次請求一個資源時,服務器在返回該資源的同時,會把上面這兩個屬性放在response header中。比如:

注意:這兩個response header屬性可以只啟用一個,也可以同時啟用。當response header中,Expires和Cache-Control同時存在時,Cache-Control的優先級高於Expires。
下面講一下二者的區別。
1、Expires:服務器返回的絕對時間。
是較老的強緩存管理 response header。瀏覽器再次請求這個資源時,先從緩存中尋找,找到這個資源后,拿出它的Expires跟當前的請求時間比較,如果請求時間在Expires的時間之前,就能命中緩存,否則就不行。
如果緩存沒有命中,瀏覽器直接從服務器請求資源時,Expires Header在重新請求的時候會被更新。
缺點:
由於Expires是服務器返回的一個絕對時間,存在的問題是:服務器的事件和客戶端的事件可能不一致。在服務器時間與客戶端時間相差較大時,緩存管理容易出現問題,比如隨意修改客戶端時間,就能影響緩存命中的結果。所以,在http1.1中,提出了一個新的response header,就是Cache-Control。
2、Cache-Control:服務器返回的相對時間。
http1.1中新增的 response header。瀏覽器第一次請求資源之后,在接下來的相對時間之內,都可以利用本地緩存。超出這個時間之后,則不能命中緩存。重新請求時,Cache-Control會被更新。
協商緩存
協商緩存:瀏覽器發現本地有資源的副本,但是不太確定要不要使用,於是去問問服務器。
當瀏覽器對某個資源的請求沒有命中強緩存(也就是說超出時間了),就會發一個請求到服務器,驗證協商緩存是否命中。
協商緩存是利用的是兩對Header:
-
第一對:
Last-Modified、If-Modified-Since -
第二對:
ETag、If-None-Match
1、Last-Modified、If-Modified-Since。過程如下:
(1)瀏覽器第一次請求一個資源,服務器在返回這個資源的同時,會加上Last-Modified這個 response header,這個header表示這該資源在服務器上的最后修改時間:

(2)瀏覽器再次請求這個資源時,會加上If-Modified-Since這個 request header,這個header的值就是上一次返回的Last-Modified的值:

(3)服務器收到第二次請求時,會比對瀏覽器傳過來的If-Modified-Since和資源在服務器上的最后修改時間Last-Modified,判斷資源是否有變化。如果沒有變化則返回304 Not Modified,但不返回資源內容(此時,服務器不會返回 Last-Modified 這個 response header);如果有變化,就正常返回資源內容(繼續重復整個流程)。這是服務器返回304時的response header:

(4)瀏覽器如果收到304的響應,就會從緩存中加載資源。
缺點:
Last-Modified、If-Modified-Since一般來說都是非常可靠的,但有可能出現的問題是:服務器上的資源變化了,但是最后的修改時間卻沒有變化。這一對header就無法解決這種情況。於是,下面這一對header出場了。
2、ETag、If-None-Match。過程如下:
(1)瀏覽器第一次請求一個資源,服務器在返回這個資源的同時,會加上ETag這個 response header,這個header是服務器根據當前請求的資源生成的唯一標識。這個唯一標識是一個字符串,只要資源有變化這個串就不同,跟最后修改時間無關,所以也就很好地補充了Last-Modified的不足。如下:

(2)瀏覽器再次請求這個資源時,會加上If-None-Match這個 request header,這個header的值就是上一次返回的ETag的值:

3)服務器第二次請求時,會對比瀏覽器傳過來的If-None-Match和服務器重新生成的一個新的ETag,判斷資源是否有變化。如果沒有變化則返回304 Not Modified,但不返回資源內容(此時,由於ETag重新生成過,response header中還會把這個ETag返回,即使這個ETag並無變化)。如果有變化,就正常返回資源內容(繼續重復整個流程)。這是服務器返回304時的response header:

(4)瀏覽器如果收到304的響應,就會從緩存中加載資源。
提示:如果面試官問你:與瀏覽器緩存相關的http header有哪些?你能寫出來嗎?這是一個亮點。
參考鏈接:
- 瀏覽器緩存知識小結及應用[薦]
四、使用CDN
怎么最快地讓用戶請求資源。一方面是讓資源在傳輸的過程中變小,另外就是CDN。
要注意,瀏覽器第一次打開頁面的時候,瀏覽器緩存是起不了作任何用的,使用CDN,效果就很明顯。
五、DNS預解析(dns-prefetch)
通過 DNS 預解析來告訴瀏覽器未來我們可能從某個特定的 URL 獲取資源,當瀏覽器真正使用到該域中的某個資源時就可以盡快地完成 DNS 解析。
第一步:打開或關閉DNS預解析
你可以通過在服務器端發送 X-DNS-Prefetch-Control 報頭。或是在文檔中使用值為 http-equiv 的meta標簽:
<meta http-equiv="x-dns-prefetch-control" content="on">
需要說明的是,在一些高級瀏覽器中,頁面中所有的超鏈接(<a>標簽),默認打開了DNS預解析。但是,如果頁面中采用的https協議,很多瀏覽器是默認關閉了超鏈接的DNS預解析。如果加了上面這行代碼,則表明強制打開瀏覽器的預解析。(如果你能在面試中把這句話說出來,則一定是你出彩的地方)
第二步:對指定的域名進行DNS預解析
如果我們將來可能從 smyhvae.com 獲取圖片或音頻資源,那么可以在文檔頂部的 標簽中加入以下內容:
<link rel="dns-prefetch" href="http://www.smyhvae.com/">
當我們從該 URL 請求一個資源時,就不再需要等待 DNS 解析的過程。該技術對使用第三方資源特別有用。
參考鏈接:
我的公眾號
想學習代碼之外的軟技能?不妨關注我的微信公眾號:生命團隊(id:vitateam)。
掃一掃,你將發現另一個全新的世界,而這將是一場美麗的意外:

