瀏覽器渲染原理及性能優化

大家好,我是前端嵐楓,兩個多月沒更新博客了,這段時間在忙著找工作,入職新公司,各項都有序的進行著,過年的一年算是很特殊的一年,經歷7.20暴雨,8月疫情在家辦公一個月,及后面的疫情,12月開始原公司長期放假,這些種種,真是一言難盡,但是進入2022年有個好的開始,1月入職新公司,年會抽獎中獎,緊接著沒有被疫情留在鄭州,順利回家過年。新的一年開始,我的技術博文更新也會持續更新。今天主要跟大家分享我整理的瀏覽器渲染原理及性能優化:性能優化是我們工作中常遇到一些問題, 也是面試官經常提問的問題,希望下面文章對大家有所幫助。

一、進程與線程

  • 進程是操作系統資源分配的基本單位,進程中包含線程
  • 線程是由進程所管理的,為了提升瀏覽器的穩定性和安全性,瀏覽器采用了多進程模型
image.png
image.png
  • 瀏覽器進程:負責界面顯示、用戶交互、子進程管理、提供存儲等
  • 渲染進程: 每個頁面都有單獨的渲染進程,核心用于渲染頁面
  • 網絡進程:主要處理網絡資源加載(html、css、js 等)
  • GPU進程:3d繪制,提高性能
  • 插件進程:chrome中安裝的一些插件

二、從輸入URL到瀏覽器顯示頁面發生了什么

用戶輸入的關鍵字還是URL?如果是關鍵字則使用默認搜索引擎生成URL

  1. 用戶輸入url地址(關鍵字 會將關鍵字根據默認引擎生成地址)會開始導航,瀏覽器進程里面做
  2. 瀏覽器進程 :會準備一個渲染進程用戶渲染頁面
  3. 網絡進程加載資源,最終將加載的資源交給渲染進程來處理
  4. 渲染完畢顯示 ipc

網絡七層模型

  • 先去查找緩存,檢測緩存是否過期,直接返回緩存中的內容
  • 看域名是否被解析,DNS協議,將域名解析成ip地址(DNS基于UDP)ip+端口號 host
  • 請求是https SSL協商
  • ip地址來進行尋地址,排隊等待,最多能發送6個http請求
  • tcp 創建鏈接,用于傳輸(三次握手)
  • 利用tcp傳輸數據(拆分成數據包 有序)可靠、有序,服務器按照順序來接受
  • http 請求(請求行 請求頭 請求體)
  • 默認不會斷開keep-alive, 為了下次傳輸數據時候可以復用上次的創建的鏈接
  • 服務器收到數據后(響應行 響應頭 響應體)
  • 服務器返回301 302 會進行重定向操作
  • 服務器返回304 去查詢瀏覽器緩存進行返回

http 0.9 負責傳輸html 最早的時候沒有請求頭和響應頭
http 1.0 提供了 http的header 根據header 的不同來處理不同的資源
http 1.1 默認開啟了keep-alive 鏈接復用 管線化 服務器處理多個請求(隊頭阻塞問題)
http 2.0 用同一個tcp鏈接來發送數據 一個域名一個tcp(多路復用)頭部壓縮 服務器可以推送數據給服務端
http3.0 解決了tcp的隊頭阻塞問題 QUIC協議 采用了udp

渲染流程

image.png
image.png
  1. 瀏覽器無法直接使用HTML,需要將HTML轉化成DOM樹。(document)
  2. 瀏覽器無法解析純文本的css樣式,需要對css進行解析成styleSheets.(document.styleSheets)
  3. 計算出DOM樹中的每個節點的具體樣式
  4. 創建渲染(布局)樹,將DOM樹中可見節點,添加到布局樹中,并計算節點渲染到頁面的坐標位置,(layout)
  5. 通過布局樹,進行分層(根據定位屬性,transform屬性,clip屬性等)生產圖層樹
  6. 將不同圖層進行繪制,轉交給合成線程處理,最終生產頁面,并顯示到瀏覽器上(Painting Display)

查看layer并對圖層進行繪制的列表

  • css 不會阻塞html解析, 先解析html,再解析css, 樣式
  • css 放到底部,可能會導致重繪效果, 當html 渲染時候,會先掃描js 和css 渲染從上到下,邊解析邊渲染
  • 渲染DOM時,要等待樣式加載完畢
  • js會阻塞html解析,阻止DOM渲染 需要暫停DOM解析去執行js ,js可能會操作樣式,所以需要等待樣式加載完成

所以js 一般放頁面底部,css 放頭部

總結:DOM 如何生成

  • 在解析前會先執行預解析操作,會預先加載js、css等文件
  • 字節流 =》分詞器 =》Token =》根據token 生成節點 =》插入到DOM 樹中
  • 遇到js 執行過程中遇到script 標簽,HTMLParse會停止解析,(下載)執行對應的腳本
  • 在js 執行前,需要等待當前腳本之上的所有css 加載解析完畢(js是依賴css的加載)#

三、Perfomance API

image.png
image.png

image.png
image.png
// js
window.addEventListener('DOMContentLoaded', function(){
    let s = 0;
  for(let i = 0; i< 10000000; i++){
    s+=i;
  }
  setTimeout(()=>{
    document.body.appendChild(document.createtextNode('hello'))
  },1000)
})
setTimeout(()=>{
    const {
    fetchStart, //開始訪問
    requestStart, //請求的開始
    responseStart, //響應的開始
    responseEnd, //響應的結束
    domInteractive, // dom 可交互的時間點
    domContentLoadedEventEnd, //dom加載完畢
    loadEventStart //所有資源加載完畢
  } = performance.timing;
  
  let TTFB = responseStart - requestStart; //首字節返回的事件 服務器處理能力
    let TTI = domInteractive - fetchStart; //整個的一個可交互的時間
  let DCL= domContentLoadedEventEnd - fetchStart; //DOM整個加載完畢
  console.log(TTFB, TTI, DCL) //如圖一
  const paint = performance.getEnteriesByType('paint')
  console.log(paint[0].startTime); //FP

}, 3000)

//遞歸看load 的時間不能為0 mutationObserver
new PerformanceObserver((entryList)=>{
    console.log(entryList.getEntries)
}).observe({entryTypes:['element']})

圖一


image.png
image.png

圖二


image.png
image.png

四、網絡優化策略

  1. 減少HTTP請求數,合并js、css,合理內嵌js、css
  2. 合理設置服務器端緩存,提高服務器處理速度。(強制緩存、協商緩存)
  3. 避免重定向,重定向會降低響應速度(301,302)
  4. 使用dns-prefetch,進行DNS預解析
  5. 采用域名分片技術,講資源放到不同的域名下,同一個域名最多處理6個TCP鏈接問題
  6. 采用CDN加速加快訪問速度。(指派最近、高度可用)
  7. gzip壓縮優化,對傳輸資源進行體積壓縮(html,css,js)
Content-Encoding:gzip
  1. 加載數據優先級:preload(預先請求當前頁面需要的資源) prefetch(將來頁面中使用的資源),將數據緩存到HTTP緩存中
<link rel="preload" href="style.css" as="style">

五、關鍵渲染路徑

image.png
image.png
  • 重排(回流)Reflow:添加元素、刪除元素、修改大小、移動元素位置、獲取位置等相關信息都會引起重排。
  • 重繪 Repaint: 頁面中元素樣式的改變并不影響它在文檔中的位置。

1.強制同步布局問題

JavaScript強制將計算樣式和布局操作提前到當前任務中

<div id="app"></div>
<script>
  function reflow(){
    let el = documnet.getElementById('app');
    let node = doucument.createElement('h1');
    node.innerHTML = 'hello';
    el.appendChild(node);
    //獲取位置會導致重排(重新布局)
    console.log(app.offsetHeight);
    
  }
  window.addEventListener('load',function(){
    for(let i=0; i<100; i++){
        reflow()
    }
  })
  
</scpript>

減少回流和重繪

  1. 脫離文檔流
  2. 渲染時給圖片增加固定寬高
  3. 盡量使用css3動畫
  4. 可以使用will-change提取到單獨的圖層中

六、靜態文件優化

1. 圖片優化

圖片格式:

  • jpg:適合色彩豐富的照片、banner圖;不適合圖形文字、圖標(紋理有鋸齒),不支持透明
  • png: 適合純色、透明、圖標、支持半透明;不適合色彩豐富圖片,因為無損儲存會導致儲存體積大
  • gif: 適合動畫,可以動的圖標;不支持半透明,不適合存儲彩色圖片
  • webp: 適合半透明圖片,可以保證圖片質量和較小的體積
  • svg: 相比于jpg和png,它的體積更小,渲染成本過高,適合小且色彩單一的圖標

圖片優化:

  • 避免空src的圖片
  • 減小圖片尺寸,節約用戶流量
  • img標簽設置alt屬性,提升圖片加載失敗時的用戶體驗
  • 原生的loading:lazy圖片懶加載
<img loading="lazy" src="./images/1.jpg" widht="300" height="450" />
  • 不同環境下,加載不同尺寸和像素的圖片
  • 對于較大的圖片可以考慮采用漸進式圖片
  • 采用base64URL 減少圖片請求
  • 采用雪碧圖片合并圖標圖片

2. HTML優化

  1. 語義化HTML:代碼簡潔清晰,利于搜索引擎,便于團隊開發維護
  2. 提前聲明字符編碼,讓瀏覽器快速確定如何渲染網頁內容
  3. 減少HTML嵌套關系,減少DOM節點數量
  4. 刪除多余空格,空行、注釋、及無用的屬性等
  5. 避免table布局

3. css 優化

  1. 減少偽類選擇器,減少樣式層數,減少使用通配符
  2. 避免使用css表達式,css表達式會頻繁求值,當滾動頁面,或者移動鼠標時,都會重新計算(IE6,7)
background-color:expression(new Date()).getHours()%2 ? "red" : "yellow");
  1. 刪除空行、注釋、減少無意義的單位、css進行壓縮
  2. 使用外鏈css,可以對css進行緩存
  3. 添加媒體字段,只加載有效的css 文件
<link href="index.css" rel="stylesheet" media="screen and(min-width:1024px)"
  1. css contain屬性將元素進行隔離
  2. 減少@import使用,由于import采用的串行加載

4. js 優化

  1. 通過async 、defer異步加載文件
image.png
image.png
  1. 減少DOM操作,緩存訪問過的元素
  2. 操作不直接應用到DOM上,而應用到虛擬DOM上。最后一次性的應用到DOM上
  3. 使用webworker解決程序阻塞問題
  4. IntersectionOberver
const observer = new IntersectionOberver(function(changes){
    changes.forEach(function(element, index){
      if(element,intersectionRatio > 0){
      observer.unobserve(element.target);
        element.target.src = element.target,dataset.src;
      }
    });
  });
function initObserve(){
    const listItems = document.querySelectAll('img');
  listItems.forEach(function(item){
  observer.observe(item)
  })
}
initObserver

  1. 虛擬滾動 vertual-scroll-list
  2. requestAnimationFrame、requestIdleCallback
image.png
image.png
  1. 盡量避免使用eval,消耗時間久
  2. 使用事件委托,減少事件綁定個數
  3. 盡量使用canvas動畫、css動畫

七、優化策略

  • 關鍵資源個數越多,,首次頁面加載時間就會越長
  • 關鍵資源的大小,內容越小,下載時間越短
  • 優化白屏:內聯css和內聯js,移除文件下載較小文件體積
  • 預渲染,打包時候進行預渲染
  • 使用SSR加速首屏加載(耗費服務端資源),有利于SEO優化,首屏利用服務器端渲染,后續交互采用客戶端渲染

八、瀏覽器的存儲

  • cookie: cookie過期時間內一直有效,存儲大小4k左右、同時限制字段個數,不適合大量的數據存儲,每次請求會攜帶cookie,主要可以利用做身份檢查驗證

    設置cookie有效期;根據不同子域劃分cookie較少傳輸;靜態資源域名和cookie域名采用不同域名,避免靜態資源訪問時攜帶cookie

  • localStroage: chrome下最大存儲5M,除非手動清除,否則一直存在,利用localStorage存儲靜態資源

function cacheFile(url){
let fileContent = localStorage.getItem()
if(file){
  eval(fileContent)
} else {
  let xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.onload = function(){
    let responseText = xhr.responseText;
    eval(responseText);
    localStorage.setItem(url,responseText)
  }
  xhr.send()
}
}
cacheFile('/index.js')
  • sessionStorage: 會話級別存儲,可用于頁面間的傳值
  • indexDB:瀏覽器的本地數據庫(基本無上限)

九、增加體驗 PWA(Progerssive Web App)

webapp用戶體驗差(不能離線訪問),用戶粘性低(無法保存入口),pwa就是為了解決這一系列問題讓webapp具有快速,可靠,安全等特點

  • Web App Mainfset: 將網站添加到桌面、更類似native的體驗
  • Service Worker: 離線緩存內容,配合cache API
  • Push Api & Notification Api: 消息推送與提醒
  • App Shell & App Skeleton App殼、骨架屏
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,071評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,409評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,569評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,360評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,895評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,123評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,643評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,559評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,742評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,981評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,363評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,622評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,354評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,707評論 2 370

推薦閱讀更多精彩內容