從url到頁面渲染:咱們能作哪些優化

在前端面試中,有一道經典的面試題:請描述一下從url輸入到頁面渲染的過程。這道題很考察候選人的能力和知識深度, 今天咱們以這個問題爲基礎,講一下在此過程當中能作哪些優化。css

從輸入 URL 到頁面加載完成的過程

  • 首先作 DNS 查詢,若是這一步作了智能 DNS 解析的話,會提供訪問速度最快的 IP 地址回來html

  • 接下來是 TCP 握手,應用層會下發數據給傳輸層,這裏 TCP 協議會指明兩端的端口號,而後下發給網絡層。網絡層中的 IP 協議會肯定 IP 地址,而且指示了數據傳輸中如何跳轉路由器。而後包會再被封裝到數據鏈路層的數據幀結構中,最後就是物理層面的傳輸了前端

  • TCP 握手結束後會進行 TLS 握手,而後就開始正式的傳輸數據面試

  • 數據在進入服務端以前,可能還會先通過負責負載均衡的服務器,它的做用就是將請求合理的分發到多臺服務器上,這時假設服務端會響應一個 HTML 文件後端

  • 首先瀏覽器會判斷狀態碼是什麼,若是是 200 那就繼續解析,若是 400 或 500 的話就會報錯,若是 300 的話會進行重定向,這裏會有個重定向計數器,避免過屢次的重定向,超過次數也會報錯瀏覽器

  • 瀏覽器開始解析文件,若是是 gzip 格式的話會先解壓一下,而後經過文件的編碼格式知道該如何去解碼文件緩存

  • 文件解碼成功後會正式開始渲染流程,先會根據 HTML 構建 DOM 樹,有 CSS 的話會去構建 CSSOM 樹。若是遇到 script 標籤的話,會判斷是否存在 async 或者 defer ,前者會並行進行下載並執行 JS,後者會先下載文件,而後等待 HTML 解析完成後順序執行,若是以上都沒有,就會阻塞住渲染流程直到 JS 執行完畢。遇到文件下載的會去下載文件,這裏若是使用 HTTP 2.0 協議的話會極大的提升多圖的下載效率。安全

  • 初始的 HTML 被徹底加載和解析後會觸發 DOMContentLoaded 事件服務器

  • CSSOM 樹和 DOM 樹構建完成後會開始生成 Render 樹,這一步就是肯定頁面元素的佈局、樣式等等諸多方面的東西網絡

  • 在生成 Render 樹的過程當中,瀏覽器就開始調用 GPU 繪製,合成圖層,將內容顯示在屏幕上了

http優化

增長安全性:用https代替http

http詳解

http是超文本傳輸協議,可是在信息傳輸過程當中,因爲通訊使用的是明文,可能存在信息被竊取和篡改的問題。

可使用安全的https替代http

詳見Carlo大佬的博文 細說https

減小請求次數:瀏覽器緩存策略

當發送http請求時,瀏覽器首先會按順序檢查如下四項是否存在緩存

  • Memory Cache
  • Service Worker Cache
  • HTTP Cache
  • Push Cache

MemoryCache

MemoryCache,是指存在內存中的緩存。從優先級上來講,它是瀏覽器最早嘗試去命中的一種緩存。從效率上來講,它是響應速度最快的一種緩存。瀏覽器秉承的是「節約原則」,咱們發現,Base64 格式的圖片,幾乎永遠能夠被塞進 memory cache,這能夠視做瀏覽器爲節省渲染開銷的「自保行爲」;此外,體積不大的 JS、CSS 文件,也有較大地被寫入內存的概率——相比之下,較大的 JS、CSS 文件就沒有這個待遇了,內存資源是有限的,它們每每被直接甩進磁盤。

Service Worker Cache

Service Worker 是一種獨立於主線程以外的 Javascript 線程。它脫離於瀏覽器窗體,所以沒法直接訪問 DOM。這樣獨立的個性使得 Service Worker 的「我的行爲」沒法干擾頁面的性能,這個「幕後工做者」能夠幫咱們實現離線緩存、消息推送和網絡代理等功能。咱們藉助 Service worker 實現的離線緩存就稱爲 Service Worker Cache。

HTTP Cache

它又分爲強緩存和協商緩存。優先級較高的是強緩存,在命中強緩存失敗的狀況下,纔會走協商緩存。

Push Cachae

Push Cache 是指 HTTP2 在 server push 階段存在的緩存。

  • Push Cache 是緩存的最後一道防線。瀏覽器只有在 Memory Cache、HTTP Cache 和 Service Worker Cache 均未命中的狀況下才會去詢問 Push Cache。
  • Push Cache 是一種存在於會話階段的緩存,當 session 終止時,緩存也隨之釋放。
  • 不一樣的頁面只要共享了同一個 HTTP2 鏈接,那麼它們就能夠共享同一個 Push Cache。

關於瀏覽器的強緩存和協商緩存,詳見Carry的博文 前端靜態資源緩存

關於sevice Worker緩存, 詳見Carry的博文 前端靜態資源緩存之sevice worker

減小單次請求所花費的時間: CDN

CDN 的核心點有兩個,一個是緩存,一個是回源。

「緩存」就是說咱們把資源 copy 一份到 CDN 服務器上這個過程,「回源」就是說 CDN 發現本身沒有這個資源(通常是緩存的數據過時了),轉頭向根服務器(或者它的上層服務器)去要這個資源的過程。

CDN 每每被用來存放靜態資源。所謂「靜態資源」,就是像 JS、CSS、圖片等不須要業務服務器進行計算即得的資源。而「動態資源」,顧名思義是須要後端實時動態生成的資源,較爲常見的就是 JSP、ASP 或者依賴服務端渲染獲得的 HTML 頁面。

那「非純靜態資源」呢?它是指須要服務器在頁面以外做額外計算的 HTML 頁面。具體來講,當我打開某一網站以前,該網站須要經過權限認證等一系列手段確認個人身份、進而決定是否要把 HTML 頁面呈現給我。這種狀況下 HTML 確實是靜態的,但它和業務服務器的操做耦合,咱們把它丟到CDN 上顯然是不合適的。

另外,CDN的域名必須和主業務服務器的域名不同,要不,同一個域名下面的Cookie各處跑,浪費了性能流量的開銷,CDN域名放在不一樣的域名下,能夠完美地避免了沒必要要的 Cookie 的出現!

渲染優化

瀏覽器的渲染機制通常分爲如下幾個步驟:

  • 處理 HTML 並構建 DOM 樹。
  • 處理 CSS 構建 CSSOM 樹
  • 將 DOM 與 CSSOM 合併成一個渲染樹。
  • 根據渲染樹來佈局,計算每一個節點的位置。
  • 調用 GPU 繪製,合成圖層,顯示在屏幕上

在渲染dom的時候,瀏覽器實際上所作的工做是

  • 獲取DOM後分割爲多個圖層
  • 對每一個圖層的節點計算樣式結果(Recalculate style–樣式重計算)
  • 爲每一個節點生成圖形和位置(Layout–迴流和重佈局)
  • 將每一個節點繪製填充到圖層位圖中(Paint Setup和Paint–重繪)
  • 圖層做爲紋理上傳至GPU
  • 複合多個圖層到頁面上生成最終屏幕圖像(Composite Layers–圖層重組)

服務端渲染

css優化建議

CSS 是阻塞的資源。瀏覽器在構建 CSSOM 的過程當中,不會渲染任何已處理的內容。即使 DOM 已經解析完畢了,只要 CSSOM 不 OK,那麼渲染這個事情就不 OK。咱們將 CSS 放在 head 標籤裏 和儘快 啓用 CDN 實現靜態資源加載速度的優化。 CSS 選擇符是從右到左進行匹配的,好比 #myList li {}實際開銷至關高。

  • 避免使用通配符,只對須要用到的元素進行選擇。
  • 關注能夠經過繼承實現的屬性,避免重複匹配重複定義。
  • 少用標籤選擇器。若是能夠,用類選擇器替代。錯誤:#dataList li{} 正確:.dataList{}
  • 不要多此一舉,id 和 class 選擇器不該該被多餘的標籤選擇器拖後腿。錯誤:.dataList#title 正確:#title
  • 減小嵌套。後代選擇器的開銷是最高的,所以咱們應該儘可能將選擇器的深度降到最低(最高不要超過三層),儘量使用類來關聯每個標籤元素。

js阻塞和Event Loop

JS 引擎是獨立於渲染引擎存在的。咱們的 JS 代碼在文檔的何處插入,就在何處執行。當 HTML 解析器遇到一個 script 標籤時,它會暫停渲染過程,將控制權交給 JS 引擎。

JS 引擎對內聯的 JS 代碼會直接執行,對外部 JS 文件還要先獲取到腳本、再進行執行。等 JS 引擎運行完畢,瀏覽器又會把控制權還給渲染引擎,繼續 CSSOM 和 DOM 的構建。

咱們將耗時的js操做放在頁面的尾部,等待html和css渲染完畢再執行js防止js阻塞頁面渲染。

js 宏任務和微任務

  • JS中分爲同步任務和異步任務,同步任務在執行棧中執行,異步任務的回調被放在任務隊列中,等待執行棧空閒時執行。 setTimeout/setInterval,XHR/fetch的回調函數都屬於異步任務。

  • 任務棧執行一次的過程屬於一次宏任務,在一個宏任務執行結果後,在下一個宏任務執行前,GUI渲染線程開始工做,對頁面進行渲染。

  • 微任務是在一次宏任務執行完畢以後,GUI線程執行以前執行的任務。當宏任務執行完,會在渲染前,將執行期間所產生的全部微任務都執行完. Promise,process.nextTick等,屬於微任務

合理的安排宏任務微任務以及dom操做的順序,能夠儘量的減小無效的dom操做。

更多關於js和Event Loop的知識,請參考雲中橋大佬的博文 從多線程到Event Loop全面梳理

迴流和重繪

  • 迴流:當咱們對 DOM 的修改引起了 DOM 幾何尺寸的變化(好比修改元素的寬、高或隱藏元素等)時,瀏覽器須要從新計算元素的幾何屬性(其餘元素的幾何屬性和位置也會所以受到影響),而後再將計算的結果繪製出來。這個過程就是迴流(也叫重排)。

  • 重繪:當咱們對 DOM 的修改致使了樣式的變化、卻並未影響其幾何屬性(好比修改了顏色或背景色)時,瀏覽器不需從新計算元素的幾何屬性、直接爲該元素繪製新的樣式(跳過了上圖所示的迴流環節)。這個過程叫作重繪。

重繪不必定致使迴流,迴流必定會致使重繪。迴流比重繪作的事情更多,帶來的開銷也更大。在開發中,要從代碼層面出發,儘量把迴流和重繪的次數最小化。

負載均衡: session複製

相關文章
相關標籤/搜索