評價頁面性能好壞的核心之一就是頁面的加載速度,而頁面加載速度的關鍵就是頁面資源的加載。本文將從瀏覽器瀏覽器頁面資源加載過程展開分析,來引出頁面關鍵請求路徑的概念,並給出如何優化該關鍵請求路徑的一些方法。 下面相關內容,都是以chrome瀏覽器爲例來進行介紹的。不一樣瀏覽器之間,能夠會略有差別,但基本過程是一致的。css
首先拋出兩個問題:html
chrome瀏覽器會將資源分爲14類,以下表所示。前端
類型 | 介紹 |
---|---|
kMainResource | 即主資源,html頁面文件資源就屬於該類型 |
kImage | 各類圖片資源 |
kCSSStyleSheet | 顧名思義,就是層疊樣式表css資源 |
kScript | 腳本資源,例如js資源 |
kFont | 字體資源,例如網頁中經常使用的字體集.woff資源 |
kRaw | 混合類型資源,最多見的ajax請求就屬於這類資源 |
kSVGDocument | SVG可縮放矢量圖形文件資源 |
kXSLStyleSheet | 擴展樣式表語言XSLT,是一種轉換語言,關於該類型能夠查閱w3c XSL來了解 |
kLinkPrefetch | HTML5頁面的預讀取資源(Link prefetch),例如dns-prefetch。下面會有詳細介紹 |
kTextTrack | video的字幕資源,- 即<track> 標籤 |
kImportResource | HTML Imports,將一個HTML文件導入到其餘HTML文檔中,例如<link href="import/post.html" rel="import" /> 。詳細瞭解請查閱相關文檔。 |
kMedia | 多媒體資源,video or audio都屬於該類資源 |
kManifest | HTML5 應用程序緩存資源 |
kMock | 預留的測試類型 |
網頁安全政策(Content Security Policy,縮寫 CSP)是由瀏覽器提供的一種白名單制度。開發者經過配置,來告訴瀏覽器各種外部資源的加載和執行限制,來提升網頁的安全性。一種最經常使用的應用就是經過限制非信任域名腳本的加載來預防XSS攻擊。 能夠經過兩種方式來配置CSP。 第一種,就是經過頁面HTTP請求頭的Content-Security-Policy字段來限制。以下圖所示,這是www.google.com頁面的請求頭: web
第二種是,經過<meta>
標籤來設置。
<meta>
是以key-value的方式來進行配置的。下面以幾個具體的應用例子來介紹。
<meta http-equiv="Content-Security-Policy" content="script-src 'self'; style-src nos.netease.com kaola.com;"> 複製代碼
上面的script-src
表明腳本資源;style-src
表明樣式資源;'self'
表明只信任當前域名下的外來資源,其餘域下的資源所有會被攔截;nos.netease.com kaola.com
表明信任nos.netease.com和kaola.com這兩個域名下的資源。 因此上面的標籤的意義就是:對於腳本資源只信任本域下的,對於樣式資源,除了本域還會加載nos.netease.com和kaola.com這兩個域名下的。ajax
<meta http-equiv="Content-Secur****ity-Policy" content="upgrade-insecure-requests"> 複製代碼
上面的upgrade-insecure-requests
的意義,就如同字面意思同樣:升級全部非安全請求。當加了這個meta標籤之後,瀏覽器會將https頁面中的全部htttp請自動升級到https。例如,當咱們須要進行全站http轉https改造時,對於原有的大量http資源會直接強制以https或wss等SSL加密形式發送請求而不會報錯。固然若是資源服務器不支持https等SSL加密,那麼該資源仍是不會載入。chrome
<meta http-equiv="Content-Security-Policy" content="block-all-mixed-content"> 複製代碼
混合內容(Mixed Content)就是第2個例子所說的,在https站點中,進行的http請求。這類在安全連接中混合了非安全請求內容就叫混合內容。出現這類請求時,咱們能夠在瀏覽器控制檯中找到對應的警告信息,以下圖所示。 json
混合內容會下降HTTPS網站的安全性和用戶體驗。不過讓人略感放心的是,瀏覽器對於可能對安全性形成較大威脅的資源類型的混合模式請求都會直接攔截報錯,例如腳本資源,以下圖所示。但對於圖片、音頻、視頻等資源只會警告,但不會阻止其加載。 對於安全性要求極高的網站,能夠經過上面的標籤來阻止因此類型的非安全連接請求,這樣包括圖片、音頻、視頻等資源也將會被攔截報錯。 固然對於Content-Security-Policy的設置還有不少其餘做用,你們能夠經過 MDN來作進一步瞭解。資源的優先級被分爲5級。不一樣資料上,對這5級的命名描述上可能有所不一樣。主要是由於資料自己多是從網絡層面,瀏覽器內核或者用戶端控制檯顯示這三個方向中的某一個來講的。這三個方向雖然對這5級的命名不一樣,但都是一一對應的。 網絡層面,5級分別爲:Highest、Medium、Low、Lowest、Idle; 瀏覽器內核,5級分別爲:VeryHigh、High、Medium、Low、VeryLow; 用戶端控制檯顯示,5級分別爲:Highest、High、Medium、Low、Lowest;後端
下面是以瀏覽器內核做爲研究方向,來介紹瀏覽器的資源優先級計算過程:瀏覽器
<link rel=「preload">
標籤預加載)、script、xhr請求;(標記early**)
它會被定爲High優先級,在以後的(標記late**)
會被設置爲Medium優先級。 下圖總結了資源優先級計算後各種資源的優先級狀況,其中特別將上面講的三種常見資源的狀況框了出來。紅框框中的爲腳本類型、紫框的爲圖片類型、藍框爲XHR請求。圖片來源點此。
上面詳細介紹了瀏覽器的資源加載過程,其中核心在於資源的加載優先順序的計算。咱們能夠經過優化資源的加載優先級順序,來有效提升頁面的加載響應速度。緩存
首先來介紹下關鍵請求鏈(Critical-Request-Chains)的概念。可視區域渲染完畢(首屏),並對於用戶來講可用時,必須加載的資源請求隊列,就叫作關鍵請求鏈。這樣,咱們能夠經過關鍵請求鏈,來肯定優先加載的資源以及加載順序,以實現瀏覽器儘量快地加載頁面。
優化關鍵請求鏈有不少方法,這裏主要介紹兩種。
第一種:利用Preload和Prefetch。
這兩個標籤在文章前面的介紹中就已經有所介紹,它們都屬於預加載性能優化技術。對於開發人員,咱們可能比瀏覽器更加了解咱們的應用。從而可使用該技術來預先告知瀏覽器某些資源可能在未來會被使用到,讓瀏覽器對這部分資源進行提早加載。 Preload:
<link rel="preload" href="test.jpg"> 複製代碼
Prefetch: Prefetch包括資源預加載、DNS預解析、http預鏈接和頁面預渲染。
資源預加載:<link rel="prefetch" href="test.css"> DNS預解析:<link rel="dns-prefetch" href="//haitao.nos.netease.com"> http預鏈接:<link rel="prefetch" href="//www.kaola.com"> 將創建對該域名的TCP連接 頁面預渲染:<link rel="prerender" href="//m.kaola.com"> 將會預先加載連接文檔的全部資源 複製代碼
那麼Prefetch和Preload有什麼區別呢? 具體來說,Preload來告訴瀏覽器預先請求當前頁須要的資源,從而提升這些資源的請求優先級。好比,對於那些原本請求優先級較低的關鍵請求,咱們能夠經過設置Prefetch來提高這些請求的優先級。 Prefetch來告訴瀏覽器用戶未來可能在其餘頁面(非本頁面)可能使用到的資源,那麼瀏覽器會在空閒時,就去預先加載這些資源放在http緩存內,最多見的dns-prefetch。好比,當咱們在瀏覽A頁面,若是會經過A頁面中的連接跳轉到B頁面,而B頁面中咱們有些資源但願儘早提早加載,那麼咱們就能夠在A頁面裏添加這些資源Prefetch,那麼當瀏覽器空閒時,就會去加載這些資源。 因此,對於那些可能在當前頁面使用到的資源能夠利用Prefetch,而對一些可能在未來的某些頁面中被使用的資源能夠利用Preload。若是從加載優先級上看,Prefetch會提高請求優先級;而Preload會把資源的優先級放在最低,當瀏覽器空閒時纔去預加載。
第二種:利用LocalStorage。 既然第一種的預加載技術來進行資源緩存的支持性較差,那麼一般能夠利用LocalStorage來對部分請求的數據和結果進行緩存,省去發送http請求所消耗的時間,從而提升網頁的響應速度。 這類作法在移動端應用已經十分普遍。下面分別介紹鵝、貓、狗三家頁面是如何利用LS來進行請求緩存的。
微信:利用LS來對js文件進行緩存。 以下圖所示,用瀏覽器打開一篇微信公衆帳號文章,打開控制檯,發現Network里居然一個js文件都不須要加載?一臉懵逼!
切到LS才譁然大悟,原來全部的JS都藏在這裏了! 微信就是利用了這種技巧來緩存關鍵路徑裏的js資源,從而大大加快了頁面訪問速度。 固然,實際實現起來,並不像表面看得那樣,第一次訪問時將js放到LS裏,每次進來取出來執行這麼簡單,最核心的實際上是須要設計一套緩存更新機制。首先咱們對於緩存的js文件要經過後綴來設置獨一無二的版本標識;其次,每次後端須要傳一份資源配置文件,前端會根據這個配置文件來和LS中緩存的文件進行版本標識匹配,從而決定是利用LS緩存,仍是從新發請求更新資源。例如,微信中的這個配置文件就是經過moon_map來同步輸出給前端的,以下圖所示:天貓:利用LS來對關鍵的XHR異步請求進行緩存。 以天貓超市首頁爲例: 以下圖,查看LS,發現其對首屏中的輪播和10個分類入口的數據進行了緩存。
上面的json內容,格式化後,發現其中包含banner和flowIcons這兩個屬性,裏面的數據分別對應的就是輪播和分類入口的數據。這樣就能夠大大提高首屏的渲染展現時間。京東:利用LS來對非關鍵請求進行緩存。 以PC版的京東首頁爲例。京東反向思惟,另闢奇徑地採用了另外一種方式來利用LS。那就是把非關鍵請求剝離出來存放在LS內。 具體來講,對於首屏數據,仍是正常加載和展現。但爲了非首屏數據的加載和渲染會阻塞和搶佔資源,從而影響首屏頁面渲染。因此將非首屏資源的HTML/CSS等資源抽出來放在LS內,當頁面滾動到可視區域時再去LS中獲取數據,插入到dom中。這點很相似於如今的模塊懶加載。以下圖所示,每一個LS裏都包含了一個模塊所須要的HTML/CSS的資源。
PS:廣告一波,網易考拉前端招人啦~有興趣的戳我投遞簡歷