成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

前端性能優化之重排和重繪

開發 前端
前言,最近利用碎片時間拜讀了一下尼古拉斯的另一巨作《高性能JavaScript》,今天寫的文章從“老生常談”的頁面重繪和重排入手,去探究這兩個概念在頁面性能提升上的作用。

[[249390]]

前言,最近利用碎片時間拜讀了一下尼古拉斯的另一巨作《高性能JavaScript》,今天寫的文章從“老生常談”的頁面重繪和重排入手,去探究這兩個概念在頁面性能提升上的作用。

一.重排 & 重繪

有經驗的大佬對這個概念一定不會陌生,“瀏覽器輸入URL發生了什么”。估計大家已經爛熟于心了,從計算機網絡到JS引擎,一路飛奔到瀏覽器渲染引擎。 經驗越多就能理解的越深。感興趣的同學可以看一下這篇文章,深度和廣度俱佳 從輸入 URL 到頁面加載的過程?如何由一道題完善自己的前端知識體系!

切回正題,我們繼續探討何為重排。瀏覽器下載完頁面所有的資源后,就要開始構建DOM樹,于此同時還會構建渲染樹(Render Tree)。(其實在構建渲染樹之前,和DOM樹同期會構建Style Tree。DOM樹與Style Tree合并為渲染樹)

  • DOM樹

表示頁面的結構

  • 渲染樹

表示頁面的節點如何顯示

 

前端性能優化之重排和重繪

 

一旦渲染樹構建完成,就要開始繪制(paint)頁面元素了。當DOM的變化引發了元素幾何屬性的變化,比如改變元素的寬高,元素的位置,導致瀏覽器不得不重新計算元素的幾何屬性,并重新構建渲染樹,這個過程稱為“重排”。完成重排后,要將重新構建的渲染樹渲染到屏幕上,這個過程就是“重繪”。簡單的說,重排負責元素的幾何屬性更新,重繪負責元素的樣式更新。而且,重排必然帶來重繪,但是重繪未必帶來重排。比如,改變某個元素的背景,這個就不涉及元素的幾何屬性,所以只發生重繪。

二. 重排觸發機制

上面已經提到了,重排發生的根本原理就是元素的幾何屬性發生了改變,那么我們就從能夠改變元素幾何屬性的角度入手

  • 添加或刪除可見的DOM元素
  • 元素位置改變
  • 元素本身的尺寸發生改變
  • 內容改變
  • 頁面渲染器初始化
  • 瀏覽器窗口大小發生改變

三. 如何進行性能優化

重繪和重排的開銷是非常昂貴的,如果我們不停的在改變頁面的布局,就會造成瀏覽器耗費大量的開銷在進行頁面的計算,這樣的話,我們頁面在用戶使用起來,就會出現明顯的卡頓?,F在的瀏覽器其實已經對重排進行了優化,比如如下代碼:

 

  1. var div = document.querySelector('.div');  
  2. div.style.width = '200px' 
  3. div.style.background = 'red' 
  4. div.style.height = '300px'

 

比較久遠的瀏覽器,這段代碼會觸發頁面2次重排,在分別設置寬高的時候,觸發2次,當代的瀏覽器對此進行了優化,這種思路類似于現在流行的MVVM框架使用的虛擬DOM,對改變的DOM節點進行依賴收集,確認沒有改變的節點,就進行一次更新。但是瀏覽器針對重排的優化雖然思路和虛擬DOM接近,但是還是有本質的區別。大多數瀏覽器通過隊列化修改并批量執行來優化重排過程。也就是說上面那段代碼其實在現在的瀏覽器優化下,只構成一次重排。

但是還是有一些特殊的元素幾何屬性會造成這種優化失效。比如:

  • offsetTop, offsetLeft,...
  • scrollTop, scrollLeft, ...
  • clientTop, clientLeft, ...
  • getComputedStyle() (currentStyle in IE)

為什么造成優化失效呢?仔細看這些屬性,都是需要實時回饋給用戶的幾何屬性或者是布局屬性,當然不能再依靠瀏覽器的優化,因此瀏覽器不得不立即執行渲染隊列中的“待處理變化”,并隨之觸發重排返回正確的值。

接下來深入的介紹幾種性能優化的小TIPS

3.1 最小化重繪和重排

既然重排&重繪是會影響頁面的性能,尤其是糟糕的JS代碼更會將重排帶來的性能問題放大。既然如此,我們首先想到的就是減少重排重繪。

3.1.1. 改變樣式

考慮下面這個例子:

 

  1. // javascript  
  2. var el = document.querySelector('.el');  
  3. el.style.borderLeft = '1px' 
  4. el.style.borderRight = '2px' 
  5. el.style.padding = '5px'

 

這個例子其實和上面那個例子是一回事兒,在最糟糕的情況下,會觸發瀏覽器三次重排。然鵝更高效的方式就是合并所有的改變一次處理。這樣就只會修改DOM節點一次,比如改為使用cssText屬性實現:

 

  1. var el = document.querySelector('.el');  
  2. el.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px'

 

沿著這個思路,聰明的老鐵一定就說了,你直接改個類名不也妥妥的。沒錯,還有一種減少重排的方法就是切換類名,而不是使用內聯樣式的cssText方法。使用切換類名就變成了這樣:

 

  1. // css  
  2. .active {  
  3. padding: 5px;  
  4. border-left: 1px;  
  5. border-right: 2px;  
  6.  
  7. // javascript  
  8. var el = document.querySelector('.el');  
  9. el.className = 'active'

 

3.1.2 批量修改DOM

如果我們需要對DOM元素進行多次修改,怎么去減少重排和重繪的次數呢?有的同學又要說了,利用上面修改樣式的方法不就行了嗎?;剡^頭看一下造成頁面重排的幾個要點里,可以明確的看到,造成元素幾何屬性發生改變就會觸發重排,現在需要增加10個節點,必然涉及到DOM的修改,這個時候就需要利用批量修改DOM這種優化方式了,這里也能看到,改變樣式最小化重繪和重排這種優化方式適用于單個存在的節點。

批量修改DOM元素的核心思想是:

  • 讓該元素脫離文檔流
  • 對其進行多重改變
  • 將元素帶回文檔中

打個比方,我們主機硬盤出現了故障,常見的辦法就是把硬盤卸下來,用專業的工具測試哪里有問題,待修復后再安裝上去。要是直接在主板上面用螺絲刀弄來弄去,估計主板一會兒也要壞了...

這個過程引發倆次重排,***步和第三步,如果沒有這兩步,可以想象一下,第二步每次對DOM的增刪都會引發一次重排。那么知道批量修改DOM的核心思想后,我們再了解三種可以使元素可以脫離文檔流的方法,注意,這里不使用css中的浮動&絕對定位,這是風馬牛不相及的概念。

  • 隱藏元素,進行修改后,然后再顯示該元素
  • 使用文檔片段創建一個子樹,然后再拷貝到文檔中
  • 將原始元素拷貝到一個獨立的節點中,操作這個節點,然后覆蓋原始元素

看一下下面這個代碼示例:

 

  1. // html  
  2. xiaomi 
  3. miui 
  4. // javascript 現在需要添加帶有如下信息的li節點  
  5. let data = [  
  6.  
  7. name'tom' 
  8. url: 'https://www.baidu.com' 
  9. },  
  10.  
  11. name'ann' 
  12. url: 'https://www.techFE.com'  
  13.  

 

首先,我們先寫一個通用的用于將新數據更新到指定節點的方法:

 

  1. // javascript  
  2. function appendNode($node, data) {  
  3. var a, li;  
  4. for(let i = 0, max = data.length; i < max; i++) {  
  5. a = document.createElement('a');  
  6. li = document.createElement('li');  
  7. a.href = data[i].url;  
  8. a.appendChild(document.createTextNode(data[i].name));  
  9. li.appendChild(a);  
  10. $node.appendChild(li);  
  11.  

 

首先我們忽視所有的重排因素,大家肯定會這么寫:

 

  1. let ul = document.querySelector('#mylist');  
  2. appendNode(ul, data); 

 

使用這種方法,在沒有任何優化的情況下,每次插入新的節點都會造成一次重排(這幾部分我們都先討論重排,因為重排是性能優化的***步)。考慮這個場景,如果我們添加的節點數量眾多,而且布局復雜,樣式復雜,那么能想到的是你的頁面一定非??D。我們利用批量修改DOM的優化手段來進行重構

1)隱藏元素,進行修改后,然后再顯示該元素

 

  1. let ul = document.querySelector('#mylist');  
  2. ul.style.display = 'none' 
  3. appendNode(ul, data);  
  4. ul.style.display = 'block'

 

這種方法造成倆次重排,分別是控制元素的顯示與隱藏。對于復雜的,數量巨大的節點段落可以考慮這種方法。為啥使用display屬性呢,因為display為none的時候,元素就不在文檔流了,還不熟悉的老鐵,手動Google一下,display:none, opacity: 0, visibility: hidden的區別

2)使用文檔片段創建一個子樹,然后再拷貝到文檔中

 

  1. let fragment = document.createDocumentFragment();  
  2. appendNode(fragment, data);  
  3. ul.appendChild(fragment); 

 

我是比較喜歡這種方法的,文檔片段是一個輕量級的document對象,它設計的目的就是用于更新,移動節點之類的任務,而且文檔片段還有一個好處就是,當向一個節點添加文檔片段時,添加的是文檔片段的子節點群,自身不會被添加進去。不同于***種方法,這個方法并不會使元素短暫消失造成邏輯問題。上面這個例子,只在添加文檔片段的時候涉及到了一次重排。

3)將原始元素拷貝到一個獨立的節點中,操作這個節點,然后覆蓋原始元素

 

  1. let old = document.querySelector('#mylist');  
  2. let clone = old.cloneNode(true);  
  3. appendNode(clone, data);  
  4. old.parentNode.replaceChild(clone, old); 

 

可以看到這種方法也是只有一次重排。總的來說,使用文檔片段,可以操作更少的DOM(對比使用克隆節點),最小化重排重繪次數。

3.1.3 緩存布局信息

緩存布局信息這個概念,在《高性能JavaScript》DOM性能優化中,多次提到類似的思想,比如我現在要得到頁面ul節點下面的100個li節點,***的辦法就是***次獲取后就保存起來,減少DOM的訪問以提升性能,緩存布局信息也是同樣的概念。前面有講到,當訪問諸如offsetLeft,clientTop這種屬性時,會沖破瀏覽器自有的優化————通過隊列化修改和批量運行的方法,減少重排/重繪版次。所以我們應該盡量減少對布局信息的查詢次數,查詢時,將其賦值給局部變量,使用局部變量參與計算。

看以下樣例:

將元素div向右下方平移,每次移動1px,起始位置100px, 100px。性能糟糕的代碼:

 

  1. div.style.left = 1 + div.offsetLeft + 'px' 
  2. div.style.top = 1 + div.offsetTop + 'px'

 

這樣造成的問題就是,每次都會訪問div的offsetLeft,造成瀏覽器強制刷新渲染隊列以獲取***的offsetLeft值。更好的辦法就是,將這個值保存下來,避免重復取值

 

  1. current = div.offsetLeft;  
  2. div.style.left = 1 + ++current + 'px' 
  3. div.style.top = 1 + ++current + 'px';  

 

責任編輯:龐桂玉 來源: segmentfault
相關推薦

2015-08-11 09:46:26

JavaScriptDOM編程重排

2013-08-27 14:23:18

瀏覽器重繪

2022-03-16 09:02:46

渲染路徑瀏覽器重排和重繪

2021-07-26 06:57:58

重繪回流前端

2021-04-28 06:00:36

CSS contain技巧

2011-04-25 10:11:57

高性能web開發

2023-04-10 11:18:38

前端性能優化

2013-11-20 14:09:37

重繪重排瀏覽器

2019-11-01 14:00:58

前端性能優化代碼

2020-10-16 09:00:12

前端開發技術

2022-05-17 09:02:30

前端性能優化

2020-10-16 10:40:39

前端性能可視化

2022-11-16 12:03:13

性能優化前端

2021-07-05 14:55:28

前端優化圖片

2022-03-02 11:13:50

Web前端開發

2021-07-29 14:20:34

網絡優化移動互聯網數據存儲

2011-08-04 17:36:24

iPhone 重繪 繪圖

2021-11-29 11:13:45

服務器網絡性能

2022-02-16 14:10:51

服務器性能優化Linux

2019-01-16 14:50:19

回流重繪前端
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 综合视频在线 | 亚洲精品久久嫩草网站秘色 | 久久久精| 欧美另类视频 | 99精品电影 | 久久亚洲精品视频 | 欧美精品在线播放 | 91xxx在线观看 | 免费一区 | 午夜精品 | 龙珠z国语版在线观看 | 久久国产精品免费一区二区三区 | 久久久爽爽爽美女图片 | 国产一区二区 | 久久精品国产99国产精品 | 欧美成人一区二区 | 欧美一区二不卡视频 | 欧美国产精品一区二区三区 | 欧美一区二区三区在线播放 | 日一区二区 | 久久久精品一区 | 亚洲二区精品 | 久久久www成人免费无遮挡大片 | 操操操日日日 | 免费在线看黄 | 欧美片网站免费 | 日日干日日操 | 国产乱码精品1区2区3区 | 成人精品国产 | 久久99国产精一区二区三区 | 久久在线视频 | 久久久国产一区 | 亚洲成人综合在线 | 亚洲成人中文字幕 | 成人三级电影 | 一区二区伦理电影 | 亚洲毛片在线 | 性欧美hd| 亚洲精品一区二区网址 | 久久精品国产一区二区电影 | 天堂亚洲 |