本文主要介紹訪問一個網站時的流程,頁面渲染過程,包括其中涉及到的概念。 以及,我們如何去優化前端頁面,讓它訪問速度更快。(critical rendering path最佳渲染路徑)
- 開啟瀏覽器,輸入URL
- DNS解析
- 完成TCP握手
- 傳送HTTP請求
- 接收HTTP響應結果
- 瀏覽器解析HTML,CSS
- 構建物件模型,DOM tree 和 CSSOM tree,組成render tree
- 瀏覽器渲染頁面(佈局)
HTTP1.x和HTTP2
在 HTTP/1.x 中,如果客戶端要想發起多個並行請求以提升效能,則必須使用多個 TCP 連線。 這是 HTTP/1.x 交付模型的直接結果,該模型可以保證每個連線每次只交付一個響應(響應排隊)。 更糟糕的是,這種模型也會導致隊首阻塞,從而造成底層 TCP 連線的效率低下。 也就是說在目前的HTTP1.X的協議下,瀏覽器對資源的併發請求個數是有限制的。 等到HTTP2到來的時候,通過二進位制分幀層進行優化。 HTTP/2 中新的二進位制分幀層突破了這些限制,實現了完整的請求和響應複用:客戶端和伺服器可以將 HTTP 訊息分解為互不依賴的幀,然後交錯傳送,最後再在另一端把它們重新組裝起來。
優勢:
- 並行交錯地傳送多個請求,請求之間互不影響。
- 並行交錯地傳送多個響應,響應之間互不干擾。
- 使用一個連線並行傳送多個請求和響應。
但這些並不是我們能夠優化的部分。
基於現在的網路條件,我們可以採用多個CDN地址,進行不同源的併發改善優化。 這篇文章主要介紹,第六步開始我們可以優化的部分,也就是解析HTML,CSS。
瀏覽器是如何構建物件模型的?
- 位元組 → 字元 → 令牌 → 節點 → 物件模型。
- HTML標記與CSS標記都會經歷上述過程,HTML變為DOM,CSS變為CSSOM
render tree構建,佈局以及繪製
構建好render tree
之後,會過濾掉display:none
這種無需渲染的節點。將tree
渲染到頁面。
值得注意的是,每一次的dom或者造成佈局影響的變動,都會觸發 reflow(迴流/重排)
,會消耗很大的頁面資源。
reflow是由於dom或者佈局的變動而觸發,如修改了dom位置,或是寬高,margin, padding等。 repaint是樣式風格修改,不影響佈局時觸發,如改了顏色之類的
提高網頁渲染速度,主要可以減少
DOM
, CSSOM
處理, 合併render tree
,以及 減少reflow
的次數
前端頁面優化,減少reflow的方法這裡可以看看如何減少reflow的次數
對CSS的優化
根據上面的內容我們知道了,想要渲染頁面必須有render tree
,而render tree
是由DOM tree
以及CSSOM tree
組成的。
- 預設下,CSS會阻塞渲染頁面
- 我們通過
@media
等,可以讓CSS標記為不阻塞渲染 - 不論是否阻塞渲染,瀏覽器都會將CSS資源下載到客戶端
所以,為了讓頁面更快的渲染,*我們必須要儘早的將CSS資源下載到我們的客戶端。*以及使用@media
進行優化
為了獲得最佳效能,你可以使用一些inline css,這樣不會去CDN獲取資源,從而造成多次往返
對JS的優化
當 HTML 解析器遇到一個 script 標記時,它會暫停構建 DOM,將控制權移交給 JavaScript 引擎;等 JavaScript 引擎執行完畢,瀏覽器會從中斷的地方恢復 DOM 構建。
這也就是為什麼我們需要將script
tag放在頁面的底部。
/React APP一般會如此使用。因為React需要將整個APP 渲染到一個DOM節點上,如果放置在DOM之上,會造成React找不到該渲染的節點,從而報錯/
而我們一般不建議在render tree
剛剛建立的時候,就使用JS去操作DOM,從而造成reflow,也就是說,希望JS不要成為render tree
的一部分。這個時候,我們將<script>
放在頁面靠下的部分就可以不阻塞頁面的渲染。
如果你的<script>
是從CDN獲取資源,那麼等待的過程也會造成一定的阻塞。
你可以將<script>
加上 async
,讓它變為非同步載入。
為了實現最佳效能,建議去除關鍵渲染路徑中任何不必要的JavaScript
/關鍵渲染路徑是指優先顯示與當前使用者操作有關的內容。/
相關文章: