主頁 > 企業開發 > 前端最佳實踐——DOM操作

前端最佳實踐——DOM操作

2020-09-21 03:30:50 企業開發

1、瀏覽器渲染原理

在講DOM操作的最佳性能實踐之前,先介紹下瀏覽器的基本渲染原理,

分為以下四個步驟:

  • 決議HTML(HTML Parser)

  • 構建DOM樹(DOM Tree)

  • 渲染樹構建(Render Tree)

  • 繪制渲染樹(Painting)

瀏覽器請求決議(Parser) HTML 檔案,并將各標記逐個轉化成 DOM 節點(DOM Tree),同時也會決議外部 CSS 檔案以及樣式元素中的樣式資料,HTML 中這些帶有視覺指令的樣式資訊將用于創建另一個樹結構:呈現樹(Render Tree),呈現樹(Render Tree)包含多個帶有視覺屬性(如顏色和尺寸)的矩形,這些矩形的排列順序就是它們將在螢屏上顯示的順序,呈現樹(Render Tree)構建完畢之后,進入“布局”處理階段,也就是為每個節點分配一個應出現在螢屏上的確切坐標,下一個階段是繪制(Painting) - 瀏覽器會遍歷呈現樹(Render Tree),由用戶界面后端層將每個節點繪制出來,

需要著重指出的是,這是一個漸進的程序,為達到更好的用戶體驗,瀏覽器會力求盡快將內容顯示在螢屏上,它不必等到整個 HTML 檔案決議完畢之后,就會開始構建呈現樹和設定布局,在不斷接收和處理來自網路的其余內容的同時,瀏覽器會將部分內容決議并顯示出來,

2、Repaints and reflows

Repaint:可以理解為重繪或重畫,當render tree中的一些元素需要更新屬性,而這些屬性只是影響元素的外觀,風格,而不會影響布局的,例如改變背景顏色 ,則就叫稱為重繪,
Reflows:可以理解為回流、布局或者重排,當渲染樹(render Tree)中的一部分(或全部)因為元素的規模尺寸,布局,隱藏等改變而需要重新構建,這就稱為回流(reflow),也就是重新布局(relayout),

回流或者重繪何時觸發?

改變用于構建渲染樹的任何內容都可能導致重繪或回流,例如:
1、添加,洗掉,更新DOM節點
2、用display: none(回流和重繪)或者visibility: hidden隱藏節點(只有重繪,因為沒有幾何更改)
3、添加樣式表,調整樣式屬性
4、調整視窗大小,更改字體大小
5、頁面初始化的渲染
6、移動DOM元素
,,,

我們來看幾個例子:

 1  
 2 var bstyle = document.body.style; // cache
 3  
 4 bstyle.padding = "20px"; // reflow, repaint
 5  
 6 bstyle.border = "10px solid red"; // another reflow and a repaint
 7  
 8 bstyle.color = "blue"; // repaint only, no dimensions changed
 9  
10 bstyle.backgroundColor = "#fad"; // repaint
11  
12 bstyle.fontSize = "2em"; // reflow, repaint
13  
14 // new DOM element - reflow, repaint
15  
16 document.body.appendChild(document.createTextNode('dude!'));

我們可以想象一下,如果直接在渲染樹(render Tree)最后面增加或者洗掉一個節點,這對于瀏覽器渲染頁面來說無傷大雅,因為只需要在渲染樹(render Tree)的末端重繪那一部分變動的節點,但是,如果是在頁面的頂部變動一個節點,瀏覽器需要重新計算渲染樹(render Tree),導致渲染樹(render Tree)的一部分或全部發生變化,渲染樹(render Tree)重新建立后,瀏覽器會重新繪制頁面上受影響的元素,重排的代價比重繪的代價高很多,重繪會影響部分的元素,而重排則有可能影響全部的元素,

3、DOM操作最佳實踐

DOM操作帶來的頁面 Repaints 和 Reflows 是不可避免的,但可以遵循一些最佳實踐來最大限度地減少Repaints 和 Reflows,如下是一些具體的實踐方法:

3.1、合并多次的DOM操作

 1  
 2 // bad
 3  
 4 var left = 10,
 5  
 6 top = 10;
 7  
 8 el.style.left = left + "px";
 9  
10 el.style.top = top + "px";
11 
14 // better
15  
16 el.className += " theclassname";
17  
18 // better
19  
20 el.style.cssText += "; left: " + left + "px; top: " + top + "px;";

由于與渲染樹更改相關的 Repaints and Reflows 是代價非常高,因此現代瀏覽器針對頻繁的 Repaints and Reflows 有性能的優化, 一個策略是瀏覽器將設定腳本所需更改的佇列,并分批執行, 這樣,每個需要 Reflows 的幾個變化將被組合,并且將僅計算一個 Reflows , 瀏覽器可以添加排隊的更改,然后在一定時間過去或達到一定數量的更改后重繪佇列(并不是所有的瀏覽器都存在這樣的優化,推薦的方式是把DOM操作盡量合并),但有時腳本可能會阻止瀏覽器優化 Reflows ,并使其重繪佇列并執行所有批量更改, 當您請求如下樣式資訊時(并非包含全部),會發生這種情況,見下圖:

以上所有這些基本上都是請求有關節點的樣式資訊,瀏覽器必須提供最新的值, 為了做到這一點,它需要應用所有計劃的更改,重繪佇列,強行回流,所以在有大批量DOM操作時,應避免獲取DOM元素的布局資訊,使得瀏覽器針對大批量DOM操作的優化不被破壞,如果需要這些布局資訊,最好是在DOM操作之前就去獲取,

 

 1 //bad
 2  
 3 var bstyle = document.body.style;
 4  
 5 bodystyle.color = 'red';
 6  
 7 tmp = computed.backgroundColor;
 8 
 9 bodystyle.color = 'white';
10  
11 tmp = computed.backgroundImage;
12  
13 bodystyle.color = 'green';
14  
15 tmp = computed.backgroundAttachment;
16  
17 
18 //better
19  
20 tmp = computed.backgroundColor;
21  
22 tmp = computed.backgroundImage;
23  
24 tmp = computed.backgroundAttachment;
25  
26  
27 bodystyle.color = 'yellow';
28  
29 bodystyle.color = 'pink';
30  
31 bodystyle.color = 'blue';

 

3.2、讓DOM元素脫離渲染樹(render Tree)后修改

(1)使用檔案片段
DocumentFragments 是DOM節點,它們不是主DOM樹的一部分,通常的用例是創建檔案片段,將元素附加到檔案片段,然后將檔案片段附加到DOM樹,在DOM樹中,檔案片段被其所有的孩子所代替,因為檔案片段存在于記憶體中,并不在DOM樹中,所以將子元素插入到檔案片段時不會引起頁面回流(Reflow),當然,最后一步把檔案片段附加到頁面的這一步操作還是會造成回流(Reflow),

 

1 var fragment = document.createDocumentFragment();
2  
3 // 一些基于fragment的大量DOM操作
4  
5 ...
6  
7 document.getElementById('myElement').appendChild(fragment);

 

(2)通過設定DOM元素的display樣式為none來隱藏元素
原理是先隱藏元素,然后基于元素做DOM操作,經過大量的DOM操作后才把元素顯示出來,

 

 
1 var myElement = document.getElementById('myElement');
2  
3 myElement.style.display = 'none';
4  
5 // 一些基于myElement的大量DOM操作
6  
7 ...
8  
9 myElement.style.display = 'block';

 

(3)克隆DOM元素到記憶體中
這種方式是把頁面上的DOM元素克隆一份到記憶體中,然后再在記憶體中操作克隆的元素,操作完成后使用此克隆元素替換頁面中原來的DOM元素,

1 var old = document.getElementById('myElement');
2 var clone = old.cloneNode(true);
3 // 一些基于clone的大量DOM操作
4 ...
5 old.parentNode.replaceChild(clone, old);

3.3、使用區域變數快取樣式資訊

獲取DOM的樣式資訊會有性能的損耗,所以如果存在回圈呼叫,最佳的做法是盡量把這些值快取在區域變數中,

 1  
 2 // bad
 3  
 4 function resizeAllParagraphsToMatchBlockWidth() {
 5  
 6 for (var i = 0; i < paragraphs.length; i++) {
 7  
 8 paragraphs[i].style.width = box.offsetWidth + 'px';
 9  
10 }
11  
12 }
13  
14  
15  
16 // better
17  
18 var width = box.offsetWidth;
19  
20 function resizeAllParagraphsToMatchBlockWidth() {
21  
22 for (var i = 0; i < paragraphs.length; i++) {
23  
24 paragraphs[i].style.width = width + 'px';
25  
26 }
27  
28 }

3.4、 設定具有影片效果的DOM元素為固定定位

使用絕對定位使得該元素在渲染樹中成為 body 下的一個直接子節點,因此當它進行影片時,它不會影響太多其他節點,

4、dom操作性能查看

4.1.1、首先用谷歌瀏覽器打開如上的鏈接,按下F12,切換到Performance選項

4.1.2、按下ctrl + E(或者點擊小圓點)開始錄制,點擊 body 區域,待文字變成綠色后點擊“stop”停止錄制

4.1.3、選中上圖中藍色(js堆)突然升高的部分,表示剛才點擊body的程序,滾動滑鼠放大主執行緒

4.1.4、點擊圓點旁邊的clear按鈕清空,重復上述的操作,直到文字變藍色停止:

 

4.2、頻繁回流造成的影響

谷歌檔案給的例子,鏈接地址如下:animation,

優化前的代碼:

 1 var pos = m.classList.contains('down') ?
 2  
 3 m.offsetTop + distance : m.offsetTop - distance;
 4  
 5 if (pos < 0) pos = 0;
 6  
 7 if (pos > maxHeight) pos = maxHeight;
 8  
 9 m.style.top = pos + 'px';
10  
11 if (m.offsetTop === 0) {
12  
13 m.classList.remove('up');
14  
15 m.classList.add('down');
16  
17 }
18  
19 if (m.offsetTop === maxHeight) {
20  
21 m.classList.remove('down');
22  
23 m.classList.add('up');
24  
25 }

 

優化后的代碼:

 1 var pos = parseInt(m.style.top.slice(0, m.style.top.indexOf('px')));
 2  
 3 m.classList.contains('down') ? pos += distance : pos -= distance;
 4  
 5 if (pos < 0) pos = 0;
 6  
 7 if (pos > maxHeight) pos = maxHeight;
 8  
 9 m.style.top = pos + 'px';
10  
11 if (pos === 0) {
12  
13 m.classList.remove('up');
14  
15 m.classList.add('down');
16  
17 }
18  
19 if (pos === maxHeight) {
20  
21 m.classList.remove('down');
22  
23 m.classList.add('up');
24  
25 }

先節流cpu,然后加多小“谷歌”圖示,直到圖示速度明顯減慢,再點擊“Optimize”優化按鈕,可以明顯感受出差距,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/93668.html

標籤:Html/Css

上一篇:使用 sroll-snap-type 優化滾動

下一篇:CSS 了解一下

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more