日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

javascript --- [读书笔记] 回流与重绘 前端优化小结

發布時間:2023/12/10 javascript 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 javascript --- [读书笔记] 回流与重绘 前端优化小结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 瀏覽器渲染原理

請說出: 從用戶在瀏覽器地址輸入網址,到看整個頁面,中間都發生了哪些事情?

  • HTTP請求階段
  • HTTP響應階段
  • 瀏覽器渲染階段

1.1 可能用到的知識

1.1.1 進程 Process、線程 Thread、 棧內存 Stack

  • 進程: 就是開的每一個程序: QQ、網易云音樂、Typora、VSCode…

  • 線程: 一個做的好的事情.

  • 棧內存: 用來提供一個環境,供我們執行代碼

1.1.2 多任務

現代操作系統比如Mac OS X, UNIX, Linux, Windows等,都是支持"多任務"的操作系統

單核CPU執行多任務: 操作系統輪流讓各個任務交替執行,任務1執行0.01秒,切換到任務二,任務2執行0.01秒,再切換到任務3…由于CPU的執行速度很快,我們感覺就像所有任務都再同時執行一樣

多核CPU執行多任務: 真正的并行執行多任務只能在多核CPU上實現,但是,由于任務數量遠遠多于CPU的核心數量,所以,操作系統也會自動把很多任務輪流調度到每個核心上執行

有些進程不止同時干一件事情,就需要同時運行多個"子任務",我們把進程內的這些子任務稱為線程.

多個線程可以同時執行,多線程的執行方式和多進程一樣的,也是由操作系統在多個線程之間快速切換,讓每個線程都短暫地交替運行,看起來就像同時執行一樣

1.2 瀏覽器渲染原理

  • 在服務器上有程序員提前寫的項目代碼.
  • 它存放在服務器的磁盤中,標識符為 project
  • request請求階段:客戶端在瀏覽器輸入網址的時候,瀏覽器會向服務器端發送請求(DNS解析、TCP的三次握手與四次揮手、HTTPS與HTTP的區別)
  • response響應階段 :瀏覽器有個專門的端口監聽這個請求,驗證之后,將項目的源代碼返回給客戶端瀏覽器(HTTP狀態碼、304緩存、HTTP報文)
  • 客戶端瀏覽器,拿到response響應的代碼后,專門在內存中開辟一個棧內存,給代碼的執行提供環境;同時分配一個主線程,去:
  • 一行一行的解析核執行代碼.
  • <!-- 棧內存 --> 進棧 ---> <!DOCTYPE html> ---> 執行完出棧
  • 遇到 link、script、img、a、video等 標簽,主線程,開新建一個子線程去執行相應的內容.自己繼續向下執行,同時會將該異步任務放到任務隊列中
  • <!-- 棧內存 --> 進棧 ---> <link href="1.css"> ---> 會將異步任務放到 TaskQueue中 <!-- 任務隊列 --> 任務1: 請求1.css
  • 根據上述規則: 同步代碼依次執行,遇到請求資源等異步代碼,會創建一個新的子線程,去執行,并將任務放到任務隊列(TaskQueue)中,然后繼續向下執行…
  • 因此主線程相當于是一直在執行同步任務.速度會很快
  • 很快,主線程執行到頁面底部
  • <!-- 棧內存 --> 進棧 ---> </html> ---> 出棧 <!-- 任務隊列 --> 任務1: 請求1.css(未完成) 任務2: 請求2.css(未完成) ... 任務n: 請求...(未完成)
  • 當執行完畢 </html>僅僅只在內存中生產了一個DOM樹(注意,此時的異步任務還沒有執行)

  • 事件循環(Event Loop):生成DOM樹之后,主線程會在任務隊列(Task Queue)中去尋找已經準備好的異步任務,將其取出到棧內存中執行

  • <!-- 任務隊列 --> 任務1: 請求1.css(未完成) 任務2: 請求2.css(已完成) ---> 取出 ---> [棧內存] ... 任務n: 請求n(已完成)<!-- 棧內存 --> 進棧 ---> 任務2 --->
  • 步驟7的機制就是 事件循環(Event Loop), 當任務隊列中的最后一條css獲取成功且在棧內存中執行完畢之后,會在內存中生產一個CSSOM.然后瀏覽器會把 CSSOM樹核DOM樹結合在一起生成一棵 Render Tree

  • 得到渲染樹(Render Tree)之后,進行回流(Layout): 根據生成的渲染樹,計算它們在設備視口(view port)內的確切位置和大小,這個計算階段稱為回流,之后就是重繪(Painting)

  • Painting(重繪): 根據渲染樹以及回流得到的幾何信息,得到節點的絕對像素.

  • 絕對像素被分到一個圖層中,每個圖層又會被加載到GPU中形成渲染紋理,最終渲染到頁面上

  • [注] : 圖層在GPU中, transform是不會觸發repaint的,使用transform的圖層都會由 獨立的合成進程進行處理

    1.2.1 性能優化

    • (減少HTTP請求次數和數據量大小) : 資源合并與壓縮 (圖片、樣式、JS文件)
    • 圖片懶加載: 第一次回流重繪的時候,不加載圖片,當第一次渲染完成之后,當屏幕滾動到哪里,就加載對應位置的數據

    1.2.2 優化點

    • request階段: DNS解析、TCP的三次握手與四次揮手、HTTPS與HTTP的區別
    • response階段: HTTP狀態碼、304緩存、HTTP報文

    1.2.2.1 DNS預解析(Chrome瀏覽器完成)

    當用戶將鼠標停留在一個鏈接上,就預示著一個用戶的偏好以及下一步的瀏覽行為.

    • 這時,Chrome就可以提前進行DNS Lookup及TCP握手
    • 當在地址欄觸發高可能性選項時,同樣會觸發DNS lookup 和TCP預連接
    • Chrom會研究,每個人每天可能訪問的網址,并對網頁上的子資源嘗試預解析、預加載以提高用戶體驗

    1.3 性能優化

    • DOM的重繪和回流 Repaint & Reflow

    • 重繪: 元素樣式的改變 (但寬度、大小、位置等不變)

    如 outline,visibility,color,background-color等

    • 回流: 元素的大小或者位置發生了變化(當頁面布局和集合信息發生變化的時候),觸發了重新布局,導致渲染樹,重新計算布局和渲染.

    如添加或刪除可見的DOM元素;元素的位置發生變化;元素的尺寸發生變化;內容發生變化(比如文本變化或圖片被另一個不同尺寸的圖片所代替);頁面一開始渲染的時候(這個無法避免);因為回流是根據視口的大小來計算元素的位置和大小的,所以瀏覽器的窗口尺寸變化也會引發回流

    注意: 回流一定會觸發重繪,而重繪不一定會回流

    • 進可能減少 回流和重繪: 因為回流會根據當前窗口的大小計算元素的位置,然后回觸發重繪.根據渲染樹和回流的幾何位置信息,算出元素的絕對像素,進而通知GPU重新渲染.

    • 避免DOM的回流: mvvm / mvc / virtual dom / dom diff

    1.3.1 分離讀寫操作 (現代的瀏覽器都有渲染隊列的機制)

    ? offsetTop、 offsetLeft 、 offsetWidth、 offsetHeight、 clientTop、 clientLeft、 clientWidth、clientHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、getComputedStyle、currentStyle

    <style>#box {width: 100px;height: 100px;background: red;border: 10px solid green;} </style> <body><div id="box"></div><script>let box = document.getElementById('box');box.style.width = '200px';box.style.height = '200px';box.style.margin = '10px';</script> </body>
    • 當代瀏覽器,遇到了上面連續對DOM操作的代碼,會將其先存在一個隊列里面,然后一起進行一次回流.
    • 但如果遇到如下
    <script>let box = document.getElementById('box');box.style.width = '200px';console.log(box.clientWidth);box.style.height = '200px';box.style.margin = '10px'; </script>
    • 以上代碼會回流2次,因為在寫操作中穿插了讀操作,將讀操作寫在最下面可以使回流變成一次
    <script>let box = document.getElementById('box');box.style.width = '200px';box.style.height = '200px';box.style.margin = '10px';console.log(box.clientWidth); </script>

    1.3.2樣式集中改變

    display.cssText = ‘width:20px; height:20px;’

    divclassName = “box”

    • 不把樣式分開寫,統一寫

    • 使用cssText

    <script>let box = document.getElementById('box');box.style.cssText = 'width:200px;height:200px;margin:10px'; </script>
    • 使用添加類
    <style>.box{width: 200px;height: 200px;margin: 10px;} </style> <script>let box = document.getElementById('box');box.className = 'box' </script>

    1.3.3 緩存布局信息

    • 看下面代碼
    <script>box.style.width = box.clientWidth + 10 + 'px';box.style.height = box.clientHeight + 10 + 'px' </script>
    • 以上會觸發2次回流,因為在遇到clientWidth、clientHeight時,瀏覽器都會清空渲染隊列,實現一次回流

    • 改進做法:

    <script>let width = box.clientWidth + 10 + 'px';let height = box.clientHeight + 10 + 'px';box.style.width = width;box.style.height = height; </script>

    1.3.4 元素批量修改

    • 例如我們經常動態的往ul中添加li屬性, 你可能會寫出如下代碼
    <ul id="box"></ul> <script>let box = document.getElementById('box');for(let i =0; i< 5; i++){let li = document.createElement('li');li.innerHTML = i;box.appendChild(li);} </script>
    • 以上會觸發5次回流,可以將DOM操作,次數太少了看不出效果…我們嘗試觸發50000次回流,打開網頁.你會發現瀏覽器卡頓了一下,然后渲染.

    • 嘗試使用字符串拼接的方式來減少回流次數

    <ul id="strBox"></ul> <script>let strBox = document.getElement('strBox');let str = '';for(let i =0; i< 50000; i++){str += `<li>${i}</li>`;}strBox.innerHTML = str; </script>
    • 在創建50000個li的情況下, 使用第一種方式大概花費330ms,而第二種方式只需100ms

    1.3.5 硬件加速優化

    • CSS3硬件加速

    [栗子] : 將盒子向右移動100像素

    <script>box.style.left = '100px'; </script>

    使用上面技術,會使頁面產生一次回流

    但是使用transform則不會產生回流

    <script>box.style.transform = 'translateX(200)' </script>
    • 你可能會好奇,為什么使用CSS3的API,不會產生回流,CSS3硬件加速的工作原理

    • 不會引起回流重繪的屬性: transform \ opacity \ filters

    • 硬件加速可能存在的缺點: 過多使用會占用大量內存,性能消耗可能會比較嚴重、有時候會導致字體模糊等…

    1.3.6 犧牲平滑度換取速度

    • 改變動畫的最小平移單位,例如: 將原本需要1像素移動改為3像素…這樣可以減少DOM的節流和重繪

    1.4 小結

    • 從用戶在瀏覽器地址輸入網址,到看整個頁面,中間都發生了哪些事情?
  • 首先瀏覽器會根據輸入的域名,通過域名服務器得ip地址,
  • 然后會檢查本地中是否有請求的資源,并且判斷請求資源是否是最新的,如果是則返回,否則去服務器端得到資源(如果有錯誤,希望指出)
  • 得到資源后,瀏覽器會在內存中開辟一個棧內存,同時分配一個主線程去從上到下解析文檔結構,遇到 link、img等標簽會將其放在任務隊列中,繼續向下執行
  • 執行到最底部,此時生成了一個 DOM 樹,然后進入事件循環(Event Loop)
  • 事件循環: 瀏覽器從 任務隊列(Task Queue)中取出已經準備好的的任務到棧內存中逐條執行
  • 結束后會生成一棵CSSOM樹, 然后主線程會根據 DOM樹和 CSSOM樹生成一棵渲染樹(Render Tree)
  • 之后會根據 視口大小(View Port)計算出節點的幾何位置(稱為節流)
  • 之后是重繪: 根據渲染樹和 節流算出的幾何位置得到節點的確切位置.
  • 完成重繪后,主線程會將每個每個絕對位置加載到GPU中,最終渲染成紋理,呈現在頁面上.
  • 參考

    Chrome高性能的秘密:DNS預解析

    CSS3硬件加速的工作原理

    瀏覽器渲染原理

    總結

    以上是生活随笔為你收集整理的javascript --- [读书笔记] 回流与重绘 前端优化小结的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。