成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

聊一聊前端性能優化 CRP

開發 前端
今天我們結合一道非常經典的面試題:從輸入URL到頁面展示,這中間發生了什么?來從其中的某些環節,來深入談談前端性能優化 CRP。

什么是 CRP?

CRP又稱關鍵渲染路徑,引用MDN對它的解釋:

關鍵渲染路徑是指瀏覽器通過把 HTML、CSS 和 JavaScript 轉化成屏幕上的像素的步驟順序。優化關鍵渲染路徑可以提高渲染性能。關鍵渲染路徑包含了 Document Object Model (DOM),CSS Object Model (CSSOM),渲染樹和布局。

優化關鍵渲染路徑可以提升首屏渲染時間。理解和優化關鍵渲染路徑對于確保回流和重繪可以每秒 60 幀、確保高性能的用戶交互和避免無意義渲染至關重要。

如何結合CRP進行性能優化?

我想對于性能優化,大家都不陌生,無論是平時的工作還是面試,是一個老生常談的話題。

如果單純針對一些點去泛泛而談,我想是不太嚴謹的。

今天我們結合一道非常經典的面試題:從輸入URL到頁面展示,這中間發生了什么?來從其中的某些環節,來深入談談前端性能優化 CRP。

從輸入 URL 到頁面展示,這中間發生了什么?

這道題的經典程度想必不用我多說,這里我用一張圖梳理了它的大致流程:

這個過程可以大致描述為如下:

  • URI 解析
  • DNS 解析(DNS 服務器)
  • TCP 三次握手(建立客戶端和服務器端的連接通道)
  • 發送 HTTP 請求
  • 服務器處理和響應
  • TCP 四次揮手(關閉客戶端和服務器端的連接)
  • 瀏覽器解析和渲染
  • 頁面加載完成

本文我會從瀏覽器渲染過程、緩存、DNS 優化幾方面進行性能優化的說明。

瀏覽器渲染過程

1. 構建 DOM 樹

構建DOM樹的大致流程梳理為下圖:

我們以下面這段代碼為例進行分析:

  1. <!DOCTYPE html> 
  2. <html> 
  3.   <head> 
  4.     <meta name="viewport" content="width=device-width,initial-scale=1"> 
  5.     <link href="style.css" rel="stylesheet"> 
  6.     <title>構建DOM樹</title> 
  7.   </head> 
  8.   <body> 
  9.     <p>森林</p> 
  10.     <div>之晨</div> 
  11.   </body> 
  12. </html> 

首先瀏覽器從磁盤或網絡中讀取 HTML 原始字節,并根據文件的指定編碼將它們轉成字符。

然后通過分詞器將字節流轉換為 Token,在Token(也就是令牌)生成的同時,另一個流程會同時消耗這些令牌并轉換成 HTML head 這些節點對象,起始和結束令牌表明了節點之間的關系。

當所有的令牌消耗完以后就轉換成了DOM(文檔對象模型)。

最終構建出的DOM結構如下:

2. 構建 CSSOM 樹

DOM樹構建完成,接下來就是CSSOM樹的構建了。

與HTML的轉換類似,瀏覽器會去識別CSS正確的令牌,然后將這些令牌轉化成CSS節點。

子節點會繼承父節點的樣式規則,這里對應的就是層疊規則和層疊樣式表。

構建DOM樹的大致流程可梳理為下圖:

我們這里采用上面的HTML為例,假設它有如下 css:

  1. body { 
  2.   font-size: 16px; 
  3. p { 
  4.   font-weight: bold; 
  5. div { 
  6.   color: orange; 

那么最終構建出的CSSOM樹如下:

有了 DOM 和 CSSOM,接下來就可以合成布局樹(Render Tree)了。

3. 構建渲染樹

等 DOM 和 CSSOM 都構建好之后,渲染引擎就會構造布局樹。布局樹的結構基本上就是復制 DOM 樹的結構,不同之處在于 DOM 樹中那些不需要顯示的元素會被過濾掉,如 display:none 屬性的元素、head 標簽、script 標簽等。

復制好基本的布局樹結構之后,渲染引擎會為對應的 DOM 元素選擇對應的樣式信息,這個過程就是樣式計算。

4. 樣式計算

樣式計算的目的是為了計算出 DOM 節點中每個元素的具體樣式,這個階段大體可分為三步來完成。

(1) 把 CSS 轉換為瀏覽器能夠理解的結構

和 HTML 文件一樣,瀏覽器也是無法直接理解這些純文本的 CSS 樣式,所以當渲染引擎接收到 CSS 文本時,會執行一個轉換操作,將 CSS 文本轉換為瀏覽器可以理解的結構——styleSheets。

(2) 轉換樣式表中的屬性值,使其標準化

現在我們已經把現有的 CSS 文本轉化為瀏覽器可以理解的結構了,那么接下來就要對其進行屬性值的標準化操作。

什么是屬性值標準化?我們來看這樣的一段CSS:

  1. body { 
  2.   font-size: 2em; 
  3. div { 
  4.   font-weight: bold; 
  5. div { 
  6.   color: red; 

可以看到上面的 CSS 文本中有很多屬性值,如 2em、bold、red,這些類型數值不容易被渲染引擎理解,所以需要將所有值轉換為渲染引擎容易理解的、標準化的計算值,這個過程就是屬性值標準化。

那標準化后的屬性值是什么樣子的?

從圖中可以看到,2em 被解析成了 32px,bold 被解析成了 700,red 被解析成了 rgb(255,0,0)……

(3) 計算出 DOM 樹中每個節點的具體樣式

現在樣式的屬性已被標準化了,接下來就需要計算 DOM 樹中每個節點的樣式屬性了,如何計算呢?

這其中涉及到兩點:CSS 的繼承規則和層疊規則。

這里由于不是本文的重點,我簡單做下說明:

  • CSS 繼承就是每個 DOM 節點都包含有父節點的樣式
  • 層疊是 CSS 的一個基本特征,它是一個定義了如何合并來自多個源的屬性值的算法。它在 CSS 處于核心地位,CSS 的全稱“層疊樣式表”正是強調了這一點。

樣式計算完成之后,渲染引擎還需要計算布局樹中每個元素對應的幾何位置,這個過程就是計算布局。

5. 計算布局

現在,我們有 DOM 樹和 DOM 樹中元素的樣式,但這還不足以顯示頁面,因為我們還不知道 DOM 元素的幾何位置信息。那么接下來就需要計算出 DOM 樹中可見元素的幾何位置,我們把這個計算過程叫做布局。

6. 繪制

通過樣式計算和計算布局就完成了最終布局樹的構建。再之后,就該進行后續的繪制操作了。

到這里,瀏覽器的渲染過程就基本結束了,通過下面的一張圖來梳理下:

到這里我們已經把瀏覽器解析和渲染的完整流程梳理完成了,那么這其中有那些地方可以去做性能優化呢?

從瀏覽器的渲染過程中可以做的優化點

通常一個頁面有三個階段:加載階段、交互階段和關閉階段。

  • 加載階段,是指從發出請求到渲染出完整頁面的過程,影響到這個階段的主要因素有網絡和 JavaScript 腳本。
  • 交互階段,主要是從頁面加載完成到用戶交互的整合過程,影響到這個階段的主要因素是 JavaScript 腳本。
  • 關閉階段,主要是用戶發出關閉指令后頁面所做的一些清理操作。

這里我們需要重點關注加載階段和交互階段,因為影響到我們體驗的因素主要都在這兩個階段,下面我們就來逐個詳細分析下。

1. 加載階段

我們先來分析如何系統優化加載階段中的頁面,來看一個典型的渲染流水線,如下圖所示:

通過上面對瀏覽器渲染過程的分析我們知道JavaScript、首次請求的 HTML 資源文件、CSS 文件是會阻塞首次渲染的,因為在構建 DOM 的過程中需要 HTML 和 JavaScript 文件,在構造渲染樹的過程中需要用到 CSS 文件。

這些能阻塞網頁首次渲染的資源稱為關鍵資源。而基于關鍵資源,我們可以繼續細化出三個影響頁面首次渲染的核心因素:

  • 關鍵資源個數。關鍵資源個數越多,首次頁面的加載時間就會越長。
  • 關鍵資源大小。通常情況下,所有關鍵資源的內容越小,其整個資源的下載時間也就越短,那么阻塞渲染的時間也就越短。
  • 請求關鍵資源需要多少個RTT(Round Trip Time)。RTT 是網絡中一個重要的性能指標,表示從發送端發送數據開始,到發送端收到來自接收端的確認,總共經歷的時延。

了解了影響加載過程中的幾個核心因素之后,接下來我們就可以系統性地考慮優化方案了。總的優化原則就是減少關鍵資源個數,降低關鍵資源大小,降低關鍵資源的 RTT 次數:

  • 如何減少關鍵資源的個數?一種方式是可以將 JavaScript 和 CSS 改成內聯的形式,比如上圖的 JavaScript 和 CSS,若都改成內聯模式,那么關鍵資源的個數就由 3 個減少到了 1 個。另一種方式,如果 JavaScript 代碼沒有 DOM 或者 CSSOM 的操作,則可以改成 sync 或者 defer 屬性
  • 如何減少關鍵資源的大小?可以壓縮 CSS 和 JavaScript 資源,移除 HTML、CSS、JavaScript 文件中一些注釋內容
  • 如何減少關鍵資源 RTT 的次數?可以通過減少關鍵資源的個數和減少關鍵資源的大小搭配來實現。除此之外,還可以使用 CDN 來減少每次 RTT 時長。

2. 交互階段

接下來我們再來聊聊頁面加載完成之后的交互階段以及應該如何去優化。

先來看看交互階段的渲染流水線:

其實這塊大致有以下幾點可以優化:

(1) 避免DOM的回流。也就是盡量避免重排和重繪操作。

(2) 減少 JavaScript 腳本執行時間。有時JavaScript 函數的一次執行時間可能有幾百毫秒,這就嚴重霸占了主線程執行其他渲染任務的時間。針對這種情況我們可以采用以下兩種策略:

  • 一種是將一次執行的函數分解為多個任務,使得每次的執行時間不要過久。
  • 另一種是采用 Web Workers。

(3) DOM操作相關的優化。瀏覽器有渲染引擎和JS引擎,所以當用JS操作DOM時,這兩個引擎要通過接口互相“交流”,因此每一次操作DOM(包括只是訪問DOM的屬性),都要進行引擎之間解析的開銷,所以常說要減少 DOM 操作。總結下來有以下幾點:

  • 緩存一些計算屬性,如let left = el.offsetLeft。
  • 通過DOM的class來集中改變樣式,而不是通過style一條條的去修改。
  • 分離讀寫操作。現代的瀏覽器都有渲染隊列的機制。
  • 放棄傳統操作DOM的時代,基于vue/react等采用virtual dom的框架

(4) 合理利用 CSS 合成動畫。合成動畫是直接在合成線程上執行的,這和在主線程上執行的布局、繪制等操作不同,如果主線程被 JavaScript 或者一些布局任務占用,CSS 動畫依然能繼續執行。所以要盡量利用好 CSS 合成動畫,如果能讓 CSS 處理動畫,就盡量交給 CSS 來操作。

(5) CSS選擇器優化。我們知道CSS引擎查找是從右向左匹配的。所以基于此有以下幾條優化方案:

  • 盡量不要使用通配符
  • 少用標簽選擇器
  • 盡量利用屬性繼承特性

(6) CSS屬性優化。瀏覽器繪制圖像時,CSS的計算也是耗費性能的,一些屬性需瀏覽器進行大量的計算,屬于昂貴的屬性(box-shadows、border-radius、transforms、filters、opcity、:nth-child等),這些屬性在日常開發中經常用到,所以并不是說不要用這些屬性,而是在開發中,如果有其它簡單可行的方案,那可以優先選擇沒有昂貴屬性的方案。

(7) 避免頻繁的垃圾回收。我們知道 JavaScript 使用了自動垃圾回收機制,如果在一些函數中頻繁創建臨時對象,那么垃圾回收器也會頻繁地去執行垃圾回收策略。這樣當垃圾回收操作發生時,就會占用主線程,從而影響到其他任務的執行,嚴重的話還會讓用戶產生掉幀、不流暢的感覺。

緩存

緩存可以說是性能優化中簡單高效的一種優化方式了。一個優秀的緩存策略可以縮短網頁請求資源的距離,減少延遲,并且由于緩存文件可以重復利用,還可以減少帶寬,降低網絡負荷。下圖是瀏覽器緩存的查找流程圖:

瀏覽器緩存相關的知識點還是很多的,這里我有整理一張圖:

DNS 相關優化

DNS全稱Domain Name System。它是互聯網的“通訊錄”,它記錄了域名與實際ip地址的映射關系。每次我們訪問一個網站,都要通過各級的DNS服務器查詢到該網站的服務器ip,然后才能訪問到該服務器。

DNS相關的優化一般涉及到兩點:瀏覽器DNS緩存和DNS預解析。

1. DNS緩存

一圖勝千言:

  • 瀏覽器會先檢查瀏覽器緩存(瀏覽器緩存有大小和時間限制),時間過長可能導致IP地址變化,無法解析正確IP地址,過短就會讓瀏覽器重復解析域名,一般為幾分鐘。
  • 如果瀏覽器緩存沒有對應域名,則會去操作系統緩存中查找。
  • 如果還沒有找到,域名就會發送到本地區的域名服務器(一般由互聯網供應商提供,電信、聯通之類),一般在本地區的域名服務器上都能找到了。
  • 當然也可能本地域名服務器也沒找到,那本地域名服務器就開始遞歸查找。

一般而言,瀏覽器解析DNS需要20-120ms,因此DNS解析可優化之處幾乎沒有。但存在這樣一個場景,網站有很多圖片在不同域名下,那如果在登錄頁就提前解析了之后可能會用到的域名,使解析結果緩存過,這樣縮短了DNS解析時間,提高網站整體上的訪問速度了,這就是DNS預解析。

2. DNS預解析

來看下 MDN 對于DNS預解析的定義吧:

X-DNS-Prefetch-Control 頭控制著瀏覽器的 DNS 預讀取功能。DNS 預讀取是一項使瀏覽器主動去執行域名解析的功能,其范圍包括文檔的所有鏈接,無論是圖片的,CSS 的,還是 JavaScript 等其他用戶能夠點擊的 URL。

因為預讀取會在后臺執行,所以 DNS 很可能在鏈接對應的東西出現之前就已經解析完畢。這能夠減少用戶點擊鏈接時的延遲。

我們這里就簡單看一下如何去做DNS預解析:

在頁面頭部加入,這樣瀏覽器對整個頁面進行預解析

  1. <meta http-equiv="x-dns-prefetch-control" content="on"> 

通過 link 標簽手動添加要解析的域名,比如:

  1. <link rel="dns-prefetch" href="//img10.360buyimg.com"/> 

 

責任編輯:趙寧寧 來源: 前端森林
相關推薦

2021-01-01 09:01:05

前端組件化設計

2021-11-24 22:47:07

Docker開發容器

2020-05-09 14:20:11

信息安全加密

2019-09-19 16:59:04

數據結構設計數據庫

2024-03-08 09:51:12

Linux網絡性能

2023-02-07 06:42:24

Pulsar負載均衡

2022-11-09 18:38:08

視頻清晰度

2018-06-07 13:17:12

契約測試單元測試API測試

2023-09-22 17:36:37

2021-01-28 22:31:33

分組密碼算法

2020-05-22 08:16:07

PONGPONXG-PON

2020-08-12 08:34:16

開發安全We

2022-11-26 00:00:06

裝飾者模式Component

2020-06-28 09:30:37

Linux內存操作系統

2022-10-08 11:33:56

邊緣計算云計算

2018-01-10 14:13:04

測試矩陣API測試

2019-12-17 10:06:18

CDMA高通4G

2022-03-08 16:10:38

Redis事務機制

2022-03-29 09:56:21

游戲版本運營

2020-09-08 06:54:29

Java Gradle語言
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲区在线 | 看一级毛片视频 | 中文字幕国产视频 | 亚洲在线视频 | 日本激情一区二区 | 免费黄色的视频 | 不用播放器看的av | 一区二区精品 | 亚洲图片视频一区 | 91精品国产91久久久久久吃药 | 精品动漫一区 | 午夜二区 | 日本久久精品视频 | 超碰人人插| 亚洲国产aⅴ成人精品无吗 欧美激情欧美激情在线五月 | 99久久国产综合精品麻豆 | 成人网视频 | 婷婷激情在线 | 精品一二三 | 午夜视频在线视频 | 久久精品国产久精国产 | 精品国产乱码久久久久久1区2区 | 成人免费精品 | 欧美一页| 色欧美综合| 伊人网国产| 国产日韩精品久久 | 久久成人国产 | 男人天堂网站 | 久草网在线视频 | 在线一区| 天天久久| 免费观看一区二区三区毛片 | 欧美日韩综合视频 | 五月天婷婷综合 | 日韩av一区二区在线观看 | 久久精品99| 日本不卡高清视频 | 国产欧美精品一区二区 | 日日骚网 | 精品伊人久久 |