Web性能優化筆記

網頁性能優化的目的

  1. 減少服務器壓力
  2. 增強用戶體驗,減少加載時間,通俗地說就是用戶感覺打開你的網頁很快,等待頁面資源加載的時間很短

方法

回答這題的思路要從另一道面試題:從敲回車開始到頁面展現這個過程發生了什么入手。以下是其中的一些過程:

  1. 看請求的html頁面有沒緩存,沒有就進行下面步驟
  2. dns查詢
  3. 建立TCP連接
  4. 發送HTTP請求
  5. 后臺處理
  6. 接收響應
  7. 接收完成
  8. 讀取html的DOCTYPE
  9. 逐行解析
  10. 看到<link href='#'>,<script src='#'>就會像服務器發起請求

優化以上每個步驟,這樣子整個web網頁的性能就提高了

減少dns查詢

你在瀏覽器地址欄輸入網址,通過DNS查詢得到網站真實IP。

比如你的一個網站,需要向 baidu.com 請求一個js文件,向 bootcdn.cn 請求一個css文件,這樣子就要進行2次dns查詢(沒有dns緩存的情況下),解決方法就是各種資源放在數量盡量少的域名下

域名解析的流程

  1. 瀏覽器緩存 – 瀏覽器會緩存DNS記錄一段時間
  2. 系統緩存 - 從 Hosts 文件查找是否有該域名和對應 IP。
  3. 路由器緩存 – 一般路由器也會緩存域名信息。
  4. ISP DNS 緩存 – 比如到電信的 DNS 上查找緩存。
  5. 如果都沒有找到,則向根域名服務器查找域名對應 IP,根域名服務器把請求轉發到下一級,知道找到 IP

把資源分散到不同的域名。

把資源分散到不同的域名允許你最大化并行下載數

例如chrome,只能同時向一個域名最多發8個請求,把資源分散到不同的域名允許你最大化并行下載數,但這樣子dns查詢時間就變長,和前面的“減少dns查詢“沖突了

如果文件很少,例如只有3個文件,放在1個域名下,這樣dns查詢時間就很快,此時如果把這3個文件分散到更多的域名下,速度也不會提高,因為3個請求還沒有達到chrome的只能同時向一個域名最多發請求的數量的極限

如果文件很多,例如16個文件,還全部放在1個域名下,雖然dns查詢時間很快,但請求時間會很慢,因為只能同時向一個域名最多發8個請求,那另外8個請求要等前面的請求發送完才能再發送

懶加載和預加載

懶加載就是例如打開一個網頁,viewport以下的網頁內容先不加載,等到用戶滾動看到那部分內容再加載相應的資源,好處:節省CDN費用,降低服務器壓力

預加載就是預先加載用戶即將要看到的內容,例如當你在第一頁時就預先加載第二頁的內容,這樣子用戶打開第二頁的時候就不用等待加載時間

使用CDN

cdn即內容分發網絡,例如谷歌的主服務器1在美國,在北京有個服務器2,服務器2不斷地把主服務器1上的內容復制過來(可能說得不是很準確),這樣子在北京訪問谷歌,直接訪問北京的服務器,比你訪問美國的主服務器要快

傳輸時gzip壓縮資源

HTTP/1.1開始,客戶端通過http請求中的Accept-Encoding頭部來提示支持的壓縮:

Accept-Encoding: gzip, deflate

如果服務器看到這個頭部,它可能會選用列表中的某個方法壓縮要請求的資源。服務器通過響應中的Content-Encoding頭部提示客戶端:

Content-Encoding: gzip

客戶端接收到響應后會解壓縮

gzip一般可減小響應的70%。盡可能去gzip更多(文本)類型的文件。html,腳本,樣式,xml和json等等都應該被gzip,而圖片,pdf等等不應該被gzip,因為它們本身已被壓縮過,gzip它們只是浪費cpu,甚至增加文件大小。

Cache-Control

 //后臺代碼
 if (path  ==='/js/main.js') {
   let  string  =    fs.readFileSync('./js/main.js', 'utf8');
   response.setHeader('Content-Type',   'application/javasript;charset=utf-8');
  response.setHeader('Cache-Control',   'max-age=30');
  response.write(string);
  response.end()
}

max-age=30指當第一次請求并下載/js/main.js后,30內遇到同樣/js/main.js的請求(例如刷新當前頁面),會從緩存里直接讀取main.js,不會再向服務器發請求

ETag

在典型用法中,當一個URL被請求,Web服務器會返回資源和其相應的ETag值,它會被放置在HTTP的“ETag”字段中:

ETag: "686897696a7c876b7e"


然后,客戶端可以決定是否緩存這個資源和它的ETag。以后,如果客戶端想再次請求相同的URL,將會發送一個包含已保存的ETag和“If-None-Match”字段的請求。

If-None-Match: "686897696a7c876b7e"

客戶端請求之后,服務器可能會比較客戶端的ETag和當前版本資源的ETag。如果ETag值匹配,這就意味著資源沒有改變,服務器便會發送回一個極短的響應,包含HTTP “304 未修改”的狀態。304狀態告訴客戶端,它的緩存版本是最新的,并應該使用它。

然而,如果ETag的值不匹配,這就意味著資源很可能發生了變化,那么,一個完整的響應就會被返回,包括資源的內容,就好像ETag沒有被使用。這種情況下,客戶端可以用新返回的資源和新的ETag替代先前的緩存版本。

部分的后臺Node.js示例代碼:

Snipaste_2018-04-01_16-59-49.png

上圖代碼的md5(string)能輸出string的md5值,用的是https://www.npmjs.com/package/md5 ,170k指的是string的大小

用沒有cookie的域名提供資源

當瀏覽器請求靜態圖片并把cookie一起發送到服務器時,cookie此時對服務器沒什么用處。所以這些cookie只是增加了網絡流量。所以你應該保證靜態資源的請求是沒有cookie的??梢詣摻ㄒ粋€子域名來托管所有靜態組件。

比如,你域名是www.example.org,可以把靜態資源托管在static.example.org。不過,你如果把cookie設置在頂級域名example.org下,這些cookie仍然會被傳給static.example.org。這種情況下,啟用一個全新的域名來托管靜態資源

另外一個用沒有cookie的域名提供資源的好處是,某些代理可能會阻止緩存待cookie的靜態資源請求。

減少cookie體積

  1. 后端代碼通過 Set-Cookie 響應頭設置 Cookie的內容

  2. 瀏覽器得到 Cookie 之后,每次訪問相同域名的網頁時, 每次請求的header都會帶上 Cookie,例如
    Cookie:sessionId=44438.40790818172

http cookie的使用有多種原因,比如授權和個性化。cookie的信息通過http頭部在瀏覽器和服務器端交換。盡可能減小cookie的大小來降低響應時間。

  • 消除不必要的cookie。
  • 盡可能減小cookie的大小來降低響應時間。
  • 注意設置cookie到合適的域名級別,則其它子域名不會被影響。

選擇<link>而不是@import

之前的一個最佳原則是說CSS應該在頂部來允許逐步渲染。

在IE用@import和把CSS放到頁面底部行為一致,所以最好別用

減少/最小化 http 請求數。

有以下幾個技術:

  • Combined files。合并文件,如合并js,合并css都能減少請求數。如果頁面間腳本和樣式差異很大,合并會更具挑戰性。
  • CSS Sprites。雪碧圖可以合并多個背景圖片,通過background-imagebackground-position 來顯示不同部分。
  • Inline images。使用data:url scheme來內連圖片。

使用外部JS和CSS。

真實世界中使用外部文件一般會加快頁面,因為JS和CSS文件被瀏覽器緩存了。內連的JS和CSS怎在每次HTML文檔下載時都被下載。內連減少了http請求,但增加了HTML文檔大小。另一方面,如果JS和CSS被緩存了,那么HTML文檔可以減小大小而不增加HTTP請求。

核心因素,就是JS和CSS被緩存相對于HTML文檔被請求的頻率。盡管這個因素很難被量化,但可以用不同的指標來計算。如果網站用戶每個session有多個pv,許多頁面重用相同的JS和CSS,那么有很大可能用外部JS和CSS更好。

唯一例外是內連更被主頁偏愛,如http://www.yahoo.com/
主頁每個session可能只有少量的甚至一個pv,這時候內連可能更快

對多個頁面的首頁來說,可以通過技術減少(其它頁面的)http請求。在首頁用內連,初始化后動態加載外部文件,接下來的頁面如果用到這些文件,就可以使用緩存了。

壓縮JS和CSS。

壓縮就是刪除代碼中不必要的字符來減小文件大小,從而提高加載速度。當代碼壓縮時,注釋刪除,不需要的空格(空白,換行,tab)也被刪除。

混淆是對代碼可選的優化。它比壓縮更復雜,并且可能產生bug。在對美國top10網站的調查,壓縮可減小21%,而混淆可減小25%。

除了外部腳本和樣式,內連的腳本和樣式同樣應該被壓縮。

使用事件委托

有時候頁面看起來不那么響應(響應速度慢),是因為綁定到不同元素的大量事件處理函數執行太多次。這是為什么要使用事件委托

另外,你不必等到onload事件來開始處理DOM樹,DOMContentLoaded更快。大多時候你需要的只是想訪問的元素已在DOM樹中,所以你不必等到所有圖片被下載。

優化圖片

在設計師建好圖片后,在上傳圖片到服務器前你仍可以做些事:

  • 檢查gif圖片的調色板大小是否匹配圖片顏色數。
  • 可以把gif轉成png看看有沒有變小。除了動畫,gif一般可以轉成png8。
  • 運行pngcrush或其它工具壓縮png。
  • 運行jpegtran或其它工具壓縮jpeg。

TCP 連接復用

在 HTTP/1.0 時代,每一個請求都會重新建立一個 TCP 連接,一旦響應返回,就關閉連接。 而建立一個連接,則需要進行三次握手(https的話則是9次握手),這極大的浪費了性能

因此 HTTP/1.1 新增了「keep-alive」功能,當瀏覽器建立一個 TCP 連接時,新的請求可以在上次建立的tcp連接之上發送,連接可以復用。。(現如今大多數瀏覽器默認都是開啟的)

HTTP 2.0 多路復用

HTTP/2.0 時代擁有了「多路復用」功能,意思是: 在一條連接上,我可以同時發起無數個請求,并且響應可以同時返回。

多個連接優化

問題:一個1M的JS文件,如何下載比較快?

  1. 整個文件一個JS
  2. 拆分成兩個500M的JS
  3. 拆分成4個250M的JS

理論上答案是3.這樣可以并行下載4個文件,減少了帶寬的占據,但是增加了3次TCP請求時間,在下載時間和TCP請求時間的取舍上,就要具體情況具體測試分析了。

如果是移動端就選擇方案1,因為移動端對多文件下載不友好

如果選擇第3種方案,那么引生出另一個問題:為什么不分得更多?
答:每個瀏覽器對并行下載有上限。每個域名限制最多同時進行N個下載線程。

其他

<link href=''><style><head>里面,因為無論放在那里都會阻塞html渲染(等到css文件下載并解析完才會顯示html內容),所以還不如放head里面讓css文件盡早下載

js放body最后,這樣子可以獲取html節點,且能先盡早顯示html頁面

chrome devtool的audits panel可以檢測網站的性能優化情況

參考資源:

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,577評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,486評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,852評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,600評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,944評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,108評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,652評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,385評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,616評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,798評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,205評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,537評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,334評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,570評論 2 379

推薦閱讀更多精彩內容