漫談網站優化提速
前幾天的一個晚上,在和一個偶然認識的小白,聊了半個晚上的網站加速的事情,總覺本身最後沒有講清楚,固有此文產生。css
本篇文章只涉及前端優化,暫不涉及後端操做,默認後端能抗住全部訪問,算力無限大,響應時間無限小。由於加上後端的話,這個命題不是短短的幾篇文章搞的定的,大多數都要依據具體的業務來肯定。html
本文涉及到的瀏覽器爲Chrome瀏覽器,不具備統一性,僅供參考使用。前端
用戶和網站的交互是經過瀏覽器來完成的,要談前端優化,那麼,咱們就要搞清楚,從用戶輸入了一串url之後,瀏覽器到底作了什麼。web
1. 瀏覽器如何打開一個網頁
這裏咱們先不考慮路由尋址的事情,後面咱們再細細道來,在Chrome瀏覽器中先打開F12,打開network,能夠看到一個網站從輸入url到頁面顯示,具體發送了多少請求。咱們以百度爲示例,看一下:後端
首先第一行,能夠看到瀏覽器請求了百度這個頁面的主題文件HTML,當瀏覽器收到這個HTML以後,瀏覽器和這個頁面的緣分,就此開始。瀏覽器
1.1 瀏覽器渲染流程
用戶請求的HTML文本(text/html)經過瀏覽器的網絡層到達渲染引擎後,渲染工做開始。每次一般渲染不會超過8K的數據塊,其中基礎的渲染流程圖:緩存
webkit引擎渲染的詳細流程,其餘引擎渲染流程稍有不一樣:服務器
渲染流程有四個主要步驟:網絡
-
解析HTML生成DOM樹 - 渲染引擎首先解析HTML文檔,生成DOM樹前端優化
-
構建Render樹 - 接下來無論是內聯式,外聯式仍是嵌入式引入的CSS樣式會被解析生成CSSOM樹,根據DOM樹與CSSOM樹生成另一棵用於渲染的樹-渲染樹(Render tree),
-
佈局Render樹 - 而後對渲染樹的每一個節點進行佈局處理,肯定其在屏幕上的顯示位置
-
繪製Render樹 - 最後遍歷渲染樹並用UI後端層將每個節點繪製出來
以上步驟是一個漸進的過程,爲了提升用戶體驗,渲染引擎試圖儘量快的把結果顯示給最終用戶。它不會等到全部HTML都被解析完才建立並佈局渲染樹。它會在從網絡層獲取文檔內容的同時把已經接收到的局部內容先展現出來。
1.2 渲染細節
瀏覽器渲染一個頁面的過程叫作「關鍵渲染路徑(Critical Rendering Path 簡稱CRP)」,下面咱們來聊一下什麼是CRP,這對咱們進行代碼級的優化有很大的指導意義。
- CRP的相關知識對於如何提高網站性能是至關有用的,共有6個步驟:
- 構建DOM樹
- 構建CSSOM樹
- 運行JavaScript
- 建立渲染樹
- 生成佈局
- 繪製頁面
以下圖:
下面詳細聊一下什麼是CRP,不感興趣的童鞋能夠直接跳過這一段看結論。
1.1.1 構建DOM樹
DOM(Document Object Model)樹是一個表示整個解析過的HTML頁面的對象,從根節點<html>開始,會建立頁面中的每一個元素/文本節點。
舉個栗子:
<html> <head> <title>Understanding the Critical Rendering Path</title> <link rel="stylesheet" href="style.css"> </head> <body> <header> <h1>Understanding the Critical Rendering Path</h1> </header> <main> <h2>Introduction</h2> <p>Lorem ipsum dolor sit amet</p> </main> <footer> <small>Copyright 2017</small> </footer> </body> </html>
上面的 HTML 將會被解析成下面的DOM樹:
HTML的優勢在於它沒必要等待整個頁面加載完成才呈現頁面,能夠解析一部分,顯示一部分。
- 可是像CSS、JavaScript等其餘資源會阻止頁面渲染。
1.1.2 構建CSSOM樹
CSSOM(CSS Object Model) 是一個跟DOM相關的樣式對象。它跟DOM的表示方法是類似的,可是不論顯式聲明仍是隱式繼承,每一個節點都存在關聯樣式。
在上面提到的html頁面的style.css中的樣式以下
body { font-size: 18px; } header { color: plum; } h1 { font-size: 28px; } main { color: firebrick; } h2 { font-size: 20px; } footer { display: none; }
它會被構建成下面的CSSOM樹
CSS 被認爲是 「渲染阻塞資源」,它意味着若是不首先徹底解析資源,渲染樹是沒法構建的。CSS因爲它的層疊繼承的性質,不能像HTML同樣解析一部分,顯示一部分。定義在文檔後面的樣式會覆蓋或改寫以前定義的樣式,由於在整個樣式表都被解析以前,若是咱們使用了在樣式表中較早定義的樣式,那錯誤的樣式將被應用。這意味着CSS必須被所有解析以後,才能開始下一步。
1.1.3 運行JavaScript
JavaScript被認爲是解析阻塞資源,這意味着HTML的解析會被JavaScript阻塞。
當解析器解析到 <script> 標籤時,不管該資源是內部仍是外鏈的都會中止解析,先去下載資源。這也是爲何,當頁面內有引用JavaScript文件時,引用標籤要放到可視元素以後了。
爲避免JavaScript解析阻塞,它能夠經過設定 async 屬性來要求其異步加載。
<script async src="script.js">
1.1.4 建立渲染樹
渲染樹是DOM和CSSOM的結合體,它表明最終會渲染在頁面上的元素的結構對象。這意味着它只關注可見內容,對於被隱藏或者CSS屬性 display:none 的屬性,不會被包含在結構內。
使用上面例子的DOM和CSSOM,渲染樹被建立以下:
1.1.5 生成佈局
佈局決定了瀏覽器視窗的大小,它提供了上下文依賴的CSS樣式,如百分比或窗口的單位。視窗尺寸一般經過 <head> 標籤中的 <meta> 中的 viewport 設定來決定。若是不存在該標籤,則一般默認爲 980px
例如,最經常使用的 meta veiwport 的值將會被設置爲和設備寬度相符:
<meta name="viewport" content="width=device-width,initial-scale=1">
若是用戶訪問網頁的設備寬度爲1000px。而後總體視窗尺寸就會基於這個寬度值了,好比 50% 就是500px, 10vw 就是100px 等等。
1.1.6 繪製頁面
最後,在繪製頁面步驟。頁面上的全部可見內容都會被轉換爲像素並呈如今屏幕上。
具體的繪製時間跟DOM數以及應用的樣式有關。有些樣式會花費更多的執行時間,好比複雜的漸變背景圖片所須要的計算時間遠超過簡單固定背景色。
1.2 總結
縱觀整個CRP流程,CSS,JS等靜態資源加載是阻塞式的,而咱們的目標是讓整個頁面最快呈如今用戶面前,並可使用,而一個頁面的呈現和HTML、CSS息息相關,那麼這兩個必定是要最早被加載的:
- 關鍵的css須要放在html的頭部位置,保證被最早加載,加載完成後能夠開始渲染頁面。
JS只是關係了網站的一些交互操做,包括一些動態效果,那麼:
- js應該放在html的最下部,和渲染視圖脫離,保證視圖渲染完成後再加載js,同時,js應儘可能保持異步加載,不要阻塞主線程。
頁面除了HTML,JS,CSS還有一個使用最多的那就是圖片
- 圖片要作壓縮,不少時候高清大圖並非一個好的選擇
- 圖片儘可能使用jpg格式(體積小)
- 圖片除了首屏之外,最好使用懶加載的方式,減小初次頁面渲染所須要的時間
- 小的icon整合成一張大圖,減小圖片加載請求數(使用時可使用css對圖片顯示作定位)
同時,還能夠從網絡層考慮優化方向:
- 從新review整個頁面,去除全部沒必要要的資源加載
- css樣式表能夠合併成爲一個文件,減小瀏覽器請求數
- css樣式表須要作壓縮,減小網絡傳輸時間(具體有工具,你們能夠本身去網上找)
還有不少我一下想不到的地方,不過整體的思想就幾句話:
- 盡一切可能減小網絡請求數
- 盡一切可能減小網絡傳輸數據
- 若是以上兩點都作到了,那麼除了關鍵html和css之外,其餘資源的加載請儘可能走異步的形式。
2. 從url到瀏覽器之間到底都經歷了什麼?
上面咱們聊了瀏覽器接受到資源請求後的一些操做處理,那麼從url輸入瀏覽器到瀏覽器接收到資源中間到底都經歷了什麼,這一塊咱們能作什麼優化呢?
首先,咱們來看一下從url到瀏覽器之間到底都經歷了什麼?
- 首先,在瀏覽器地址欄中輸入url
- 瀏覽器先查看瀏覽器緩存-系統緩存-路由器緩存,若是緩存中有,會直接在屏幕中顯示頁面內容。若沒有,則跳到第三步操做。
- 在發送http請求前,須要域名解析(DNS解析),解析獲取相應的IP地址。
- 瀏覽器向服務器發起tcp鏈接,與瀏覽器創建tcp三次握手。
- 握手成功後,瀏覽器向服務器發送http請求,請求數據包。
- 服務器處理收到的請求,將數據返回至瀏覽器
- 瀏覽器收到HTTP響應
- 讀取頁面內容,瀏覽器渲染,解析html源碼
- 生成Dom樹、解析css樣式、js交互
- 客戶端和服務器交互
首先,咱們能作優化的地方只有可憐的2,包括四、五、六、七、8都是標準的處理流程,咱們也沒法干涉。
2.1 緩存查找
- 瀏覽器緩存:瀏覽器會記錄DNS一段時間,所以,只是第一個地方解析DNS請求;
- 操做系統緩存:若是在瀏覽器緩存中不包含這個記錄,則會使系統調用操做系統,獲取操做系統的記錄(保存最近的DNS查詢緩存);
- 路由器緩存:若是上述兩個步驟均不能成功獲取DNS記錄,繼續搜索路由器緩存;
- ISP緩存:若上述均失敗,繼續向ISP搜索。
小結:
- 在不多有改動的頁面上開啓瀏覽器緩存,在打開頁面時儘量的利用瀏覽器緩存
3. 網站訪問慢還有什麼可能?
網站打開速度慢受不少因素的影響,簡單概括下常見的幾個緣由:
- 主機服務器不堪重負,響應速度慢;
- 靜態資源佔用了主機服務大量的帶寬,達到了上限;
- 網站的圖片和內容太大,須要花費不少時間下載;
- 網站使用了太多不一樣的腳本和圖片,這些腳本和圖片沒有針對快速加載網站進行優化,加載時間長;
- 網站的服務器位置與終端用戶位於不一樣的地理位置。
其實還有許多其餘的緣由,但這些以上列舉的幾點是比較常見的。
3.1 終極大殺器——CDN
3.1.1 什麼是CDN?
CDN指的是內容分發網絡。其基本思路是儘量的避開互聯網上有可能影響數據傳輸速度和穩定性的瓶頸和環節,使內容傳輸的更快、更穩定。
經過在網絡各處放置節點服務器所構成的在現有的互聯網基礎之上的一層智能虛擬網絡,CDN系統可以實時地根據網絡流量和各節點的鏈接、負載情況以及到用戶的距離和響應時間等綜合信息將用戶的請求從新導向離用戶最近的服務節點上。其目的是使用戶可就近取得所需內容,解決Internet網絡擁擠的情況,提升用戶訪問網站的響應速度。
簡單打個比方,咱們常喜歡在京東上買東西,今天下單明天就能送到。而在淘寶上,咱們享受不到這樣的速度。爲何呢?由於京東的物流體系完善。假設你在上海購買了海南的一件商品,淘寶走快遞可能要走3天才到你手上,可是京東在全國設有倉庫物流點,從就近的杭州發貨點發貨到上海,一天就能夠到。
而CDN通常都由運營商或者大型雲服務提供商來提供,能夠給更大的網絡帶寬,能夠部署的離終端用戶位置更近,有智能DNS,有效緩解全部流量所有回源對咱們的主服務形成的流量衝擊,帶來更高的可用性,固然,這樣會形成靜態資源緩存,若是咱們須要更新靜態資源,面臨着緩存的挑戰,不過,也不是沒有解決方案的,全部的靜態資源在訪問的時候都應該加上版本號,防止訪問到前面版本的資源,形成更新不及時。
參考:
http://www.javashuo.com/article/p-nookqfpg-y.html
原文出處:https://www.cnblogs.com/babycomeon/p/11173611.html