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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

读书笔记 --- 再次阅读回流与重绘

發(fā)布時(shí)間:2023/12/10 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 读书笔记 --- 再次阅读回流与重绘 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

參考 - 強(qiáng)烈推薦看看,這個(gè)作者寫了很多特別好的文章.

瀏覽器渲染過程

  • 解析HTML,生成DOM樹; 解析CSS生成CSSOM樹
  • 將DOM樹和CSSOM樹合并,生成渲染(Render)樹
  • Layout(回流): 根據(jù)生成的渲染樹,視口(viewport),得到節(jié)點(diǎn)的幾何信息(位置、大小)
  • Painting(重繪): 根據(jù)渲染樹和幾何信息得到節(jié)點(diǎn)的絕對(duì)像素
  • Display: 將像素發(fā)送給GPU,展示在頁面上
  • 生成渲染樹

    為了構(gòu)建渲染樹,瀏覽器主要完成了以下工作:

  • 從DOM樹的根節(jié)點(diǎn)開始遍歷每個(gè)可見節(jié)點(diǎn)
  • 對(duì)于每個(gè)可見的節(jié)點(diǎn),找到CSSOM樹中的規(guī)則,并應(yīng)用它們
  • 根據(jù)每個(gè)可見節(jié)點(diǎn)及其對(duì)應(yīng)的樣式,組合生成渲染樹
  • 【不可見的節(jié)點(diǎn)】:

    • 一些不會(huì)渲染輸出的節(jié)點(diǎn): 比如script、meta、link等
    • 一些通過css進(jìn)行隱藏的節(jié)點(diǎn)。比如display: none。注意,利用visibility和opacity隱藏的節(jié)點(diǎn),還是會(huì)顯示在渲染樹上的。只有display:none的節(jié)點(diǎn)才不會(huì)顯示在渲染樹上

    【注意】: 渲染樹只包括可見的節(jié)點(diǎn)

    回流(Layout)

    前面將DOM節(jié)點(diǎn)以及它對(duì)應(yīng)的樣式結(jié)合起來,可是我們還需要計(jì)算它們?cè)谠O(shè)備視口(viewport)內(nèi)的確切位置和大小,這個(gè)計(jì)算的階段就是回流。看下面的栗子:

    <!DOCTYPE html> <html><head><meta name="viewport" content="width=device-width,initial-scale=1"><title>Cretical Path: Hello Marron!</title></head><body><div style="width: 50%"><div style="width: 50%">Hi Marron, best wish!</div></div></body> </html>

    我們可以看到,第一個(gè)div將節(jié)點(diǎn)的顯示尺寸設(shè)置為視口寬度的50%,第二個(gè)div將其尺寸設(shè)置為父節(jié)點(diǎn)的50%.而在回流這個(gè)階段,我們就需要根據(jù)視口具體的寬度,將其轉(zhuǎn)為實(shí)際的像素值。

    ?

    重繪 (Painting)

    • 生成渲染樹階段: 我們直到了哪些節(jié)點(diǎn)是可見的以及可見節(jié)點(diǎn)的樣式
    • 在回流階段: 我們得到了可見元素的具體幾何信息

    我們得到的信息,最終都會(huì)托付給GPU進(jìn)行渲染

    GPU的渲染需要具體的像素位置,這就是重繪階段所做的事情: 根據(jù)渲染樹和幾何信息計(jì)算出絕對(duì)像素點(diǎn).

    何時(shí)發(fā)生回流重繪

    回流主要是計(jì)算節(jié)點(diǎn)的幾何位置和幾何像素大小.那么當(dāng)頁面布局和幾何信息發(fā)生變化的時(shí)候,就需要回流:

    • 添加或刪除可見的DOM元素
    • 元素的位置發(fā)生變化
    • 元素的尺寸發(fā)生變化(內(nèi)/外邊距、邊框大小、高度和寬度等)
    • 內(nèi)容發(fā)生: 文本發(fā)生變化或圖片被另一個(gè)不同尺寸的圖片所替代
    • 頁面剛開始渲染的時(shí)候
    • 瀏覽器的窗口尺寸變化: 回流是根據(jù)視口的大小來計(jì)算元素的位置和大小的

    經(jīng)典老話: 回流一定重繪,重繪不一定回流

    瀏覽器的優(yōu)化機(jī)制

    現(xiàn)代的瀏覽器都是很聰明的,由于每次重排都會(huì)造成造成額外的計(jì)算消耗,因此大多數(shù)瀏覽器都會(huì)通過隊(duì)列修改、批量執(zhí)行來優(yōu)化重排過程。瀏覽器會(huì)將修改操作放在隊(duì)列里,直到過了一段時(shí)間,或者操作達(dá)到一個(gè)閾值,才清空隊(duì)列。

    還有一些強(qiáng)制刷新的屬性(避免使用):

    • offsetTop、offsetLeft、offsetWidth、offsetHeight
    • scrollTop、scrollLeft、scrollWidth、scrollHeight
    • clientTop、clientLeft、clientWidth、clientHeight
    • getComputedStyle()
    • getBoundingClientRect

    前端優(yōu)化

    1 -【并多次的DOM和添加樣式】

    // 未優(yōu)化前 - 3次 const el = document.getElementById('test') el.style.padding = '5px'; el.style.borderLeft = '1px'; el.style.borderRight = '2px';// 合并樣式 - 1次 const el = document.getElementById('test'); el.style.cssText += 'border-left: 1px; border-right: 2px; padding: 5px'// 添加樣式 - 1次 const el = document.getElementById('test'); el.calssName += ' active';

    2 -【脫離文檔流】

    當(dāng)元素脫離文檔流后,對(duì)元素的所有操作都不會(huì)引起回流和重繪.因此如果,對(duì)某個(gè)元素進(jìn)行的DOM操作比較多的時(shí)候,可以先將元素脫離文檔流,然后操作,最后在放回文檔流。具體操作如下:

  • 使元素脫離文檔流
  • 對(duì)其進(jìn)行多次修改
  • 將元素帶回到文檔中.
  • [注] : 上述的1、3會(huì)引起回流和重繪.

    【脫離文檔流的方法】

    • 隱藏元素,修改應(yīng)用,重新顯示
    • 使用文檔片段(document fragment)在使用DOM之外構(gòu)建一個(gè)子樹,再把它拷貝回文檔
    • 將原始元素拷貝到一個(gè)脫離文檔的節(jié)點(diǎn)中,修改節(jié)點(diǎn)后,再替換原始的元素。
    // 每次插入li都會(huì)引起一次回流和重繪 function appendDataToElement(appendToElement, data) {let li;for(let i =0,len = data.length;i < len;i++){li = document.createElement('li');li.textContent = 'text';appendToElement.appendChild(li);} }const ul = document.getElementById('list'); appdenDataToElement(ul, data);

    [隱藏元素]

    // 僅在隱藏元素和現(xiàn)實(shí)元素時(shí)產(chǎn)生2次回流和重繪 function appendDataToElement(appendToElement, data) {let li;for(let i =0, len = data.length; i < len; i++){li = document.createElement('li');li.textContent = 'text';appendTOElement.appendChild(li);} }const ul = document.getElementById('list'); ul.style.display = 'none'; appendDataToElement(ul, data); ul.style.display = 'block';

    [使用文檔片段] - 在當(dāng)前DOM外構(gòu)建一個(gè)子樹,再把它拷貝回文檔

    const ul = document.getElementById('list'); const fragment = document.createDocumentFragment(); appendDataToElement(fragment, data); up.appendChild(fragment);

    [脫離文檔] - 將原始元素拷貝到一個(gè)脫離文檔的節(jié)點(diǎn)中,修改節(jié)點(diǎn),再替換原始的元素。

    const ul = document.getElementById('list'); const clone = ul.cloneNode(true); appendDataToElement(clone, data); ul.parentNode.replaceChild(clone, ul);

    [注] - 現(xiàn)代瀏覽器使用了隊(duì)列來存儲(chǔ)多次修改,因此上述的優(yōu)化可能效果不是很理想.

    3 - 【避免觸發(fā)同步布局事件】

    // 栗子: 多次使用到 offsetWidth 屬性 function initP(){for(let i = 0; i< paragraph.length; i++){paragraph[i].style.width = box.offsetWidth + 'px'} }

    上述代碼每次循環(huán),都會(huì)使瀏覽器強(qiáng)制刷新隊(duì)列(box.offsetWidth),造成多次回流和重繪.改進(jìn)如下:

    const width = box.offsetWidth; function initP(){for(let i = 0; i < paragraph.length; i++){paragraph[i].style.width = width + 'px'} }

    4 - 【復(fù)雜動(dòng)畫的優(yōu)化】

    對(duì)于復(fù)雜動(dòng)畫效果,由于會(huì)經(jīng)常的引起回流和重繪。因此,我們可以使用絕對(duì)定位,讓它脫離文檔流。否則會(huì)引起父元素以及后續(xù)元素頻繁的回流 - 栗子

    總結(jié)

    以上是生活随笔為你收集整理的读书笔记 --- 再次阅读回流与重绘的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。