瀏覽器渲染原理及性能優(yōu)化

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

一、進程與線程

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

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

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

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

網(wǎng)絡七層模型

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

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

渲染流程

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

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

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

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

總結(jié):DOM 如何生成

  • 在解析前會先執(zhí)行預解析操作,會預先加載js、css等文件
  • 字節(jié)流 =》分詞器 =》Token =》根據(jù)token 生成節(jié)點 =》插入到DOM 樹中
  • 遇到js 執(zhí)行過程中遇到script 標簽,HTMLParse會停止解析,(下載)執(zhí)行對應的腳本
  • 在js 執(zhí)行前,需要等待當前腳本之上的所有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, //響應的結(jié)束
    domInteractive, // dom 可交互的時間點
    domContentLoadedEventEnd, //dom加載完畢
    loadEventStart //所有資源加載完畢
  } = performance.timing;
  
  let TTFB = responseStart - requestStart; //首字節(jié)返回的事件 服務器處理能力
    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

四、網(wǎng)絡優(yōu)化策略

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

五、關(guān)鍵渲染路徑

image.png
image.png
  • 重排(回流)Reflow:添加元素、刪除元素、修改大小、移動元素位置、獲取位置等相關(guān)信息都會引起重排。
  • 重繪 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提取到單獨的圖層中

六、靜態(tài)文件優(yōu)化

1. 圖片優(yōu)化

圖片格式:

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

圖片優(yōu)化:

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

2. HTML優(yōu)化

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

3. css 優(yōu)化

  1. 減少偽類選擇器,減少樣式層數(shù),減少使用通配符
  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 優(yōu)化

  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. 使用事件委托,減少事件綁定個數(shù)
  3. 盡量使用canvas動畫、css動畫

七、優(yōu)化策略

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

八、瀏覽器的存儲

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

    設(shè)置cookie有效期;根據(jù)不同子域劃分cookie較少傳輸;靜態(tài)資源域名和cookie域名采用不同域名,避免靜態(tài)資源訪問時攜帶cookie

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

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:瀏覽器的本地數(shù)據(jù)庫(基本無上限)

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

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

  • Web App Mainfset: 將網(wǎng)站添加到桌面、更類似native的體驗
  • Service Worker: 離線緩存內(nèi)容,配合cache API
  • Push Api & Notification Api: 消息推送與提醒
  • App Shell & App Skeleton App殼、骨架屏
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容