欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談DOM的操作以及性能優(yōu)化問題-重繪重排

 更新時間:2017年01月08日 08:34:02   投稿:jingxian  
下面小編就為大家?guī)硪黄獪\談DOM的操作以及性能優(yōu)化問題-重繪重排。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

寫在前面:

大家都知道DOM的操作很昂貴。 

然后貴在什么地方呢?

一、訪問DOM元素

二、修改DOM引起的重繪重排

一、訪問DOM  

像書上的比喻:把DOM和JavaScript(這里指ECMScript)各自想象為一個島嶼,它們之間用收費橋梁連接,ECMAScript每次訪問DOM,都要途徑這座橋,并交納“過橋費”,訪問DOM的次數(shù)越多,費用也就越高。因此,推薦的做法是盡量減少過橋的次數(shù),努力待在ECMAScript島上。我們不可能不用DOM的接口,那么,怎樣才能提高程序的效率?

既然無法避免,那就減少訪問。(width、offsetTop、left。。。能少就少,可以緩存起來的,就緩存)

// code1錯誤
console.time(1);
for(var i = 0; i < times; i++) {
 document.getElementById('div1').innerHTML += 'a';
}
console.timeEnd(1);
 
// code2正確
console.time(2);
var str = '';
for(var i = 0; i < times; i++) {
 str += 'a';
}
document.getElementById('div2').innerHTML = str;
console.timeEnd(2);
////////////////////////

html集合&遍歷DOM

html集合類似數(shù)組,但是跟數(shù)組還是不一樣的。如: document.getElementsByTagName('a') 返回的html集合。這個集合是實時更新的,即后面代碼修改了DOM,會反映在這個html集合里面。可嘗試代碼。


<body>
 <ul id='fruit'>
 <li> apple </li>
 <li> orange </li>
 <li> banana </li>
 </ul>
</body>
<script type="text/javascript">
 var lis = document.getElementsByTagName('li');
 var peach = document.createElement('li');
 peach.innerHTML = 'peach';
 document.getElementById('fruit').appendChild(peach);
 
 console.log(lis.length); // 4
</script>


正因為這個原因:html集合,讀取 length 屬性比數(shù)組消耗大多了。

要解決這個問題并不難,在遍歷DOM集合的時候,緩存length就好了。不要每次使用就獲取,主要體現(xiàn)在for循環(huán)中(你應該知道,for循環(huán)中,每一次都會執(zhí)行判讀語句,讀取length)

console.time(0);
var lis0 = document.getElementsByTagName('li');
var str0 = '';
for(var i = 0; i < lis0.length; i++) {
 str0 += lis0[i].innerHTML;
}
console.timeEnd(0);
 
console.time(1);
var lis1 = document.getElementsByTagName('li');
var str1 = '';
for(var i = 0, len = lis1.length; i < len; i++) {
 str1 += lis1[i].innerHTML;
}
console.timeEnd(1);

二、重繪重排

1.什么是重繪重排?

瀏覽器下載完頁面中的所有組件——HTML標記、JavaScript、CSS、圖片之后會解析生成兩個內部數(shù)據結構——DOM樹和渲染樹。

在文檔初次加載時,瀏覽器引擎通過解析 html文檔 構建一棵DOM樹,之后根據DOM元素的幾何屬性構建一棵用于展示渲染的渲染樹。渲染樹中的節(jié)點被稱為“幀”或“盒",符合CSS模型的定義,可理解為(包括理解頁面元素為一個具有大小,填充,邊距,邊框和位置的盒子)。由于隱藏元素不需要顯示,渲染樹中并不包含DOM樹中隱藏的元素(知道這點有用)。 當渲染樹構建完成,瀏覽器把每一個元素放到正確的位置上,然后再根據每一個元素的其他樣式,繪制頁面。

由于瀏覽器的流布局,對渲染樹的計算通常只需要遍歷一次就可以完成。但table及其內部元素除外,它可能需要多次計算才能確定好其在渲染樹中節(jié)點的屬性,通常要花3倍于同等元素的時間。這也是為什么我們要避免使用table做布局的一個原因。

重繪:是一個元素外觀的改變所觸發(fā)的瀏覽器行為,例如改變visibility、outline、背景色等屬性(上面說到的其他屬性)。瀏覽器會根據元素的新屬性重新繪制,使元素呈現(xiàn)新的外觀。重繪不會帶來重新布局,并不一定伴隨重排。

重排:當DOM的變化影響了元素的幾何屬性(寬或高),瀏覽器需要重新計算元素的幾何屬性,同樣其他元素的幾何屬性和位置也會因此受到影響。瀏覽器會使渲染樹中受到影響的部分失效,并重新構造渲染樹。這個過程稱為重排。重排一定伴隨著重繪。

2. 觸發(fā)重排的操作:

2.1 修改DOM元素幾何屬性:

修改元素大小,位置,內容(一般只有重繪,但是內容可能導致元素大小變化)

2.2 DOM樹結構發(fā)生變化

當DOM樹的結構變化時,例如節(jié)點的增減、移動等,也會觸發(fā)重排。瀏覽器引擎布局的過程,類似于樹的前序遍歷,是一個從上到下從左到右的過程。 通常在這個過程中,當前元素不會再影響其前面已經遍歷過的元素。所以,如果在body最前面插入一個元素,會導致整個文檔的重新渲染,而在其后插入一個元 素,則不會影響到前面的元素。

2.4 改變?yōu)g覽器大小

3.渲染樹變化的排隊和刷新

思考下面代碼:

var ele = document.getElementById('myDiv');
ele.style.borderLeft = '1px';
ele.style.borderRight = '2px';
// var _top = ele.offsetTop; //刷新隊列
ele.style.padding = '5px';

三行代碼,三次修改元素的幾何屬性,瀏覽器應該發(fā)生三次重排重繪。

但是瀏覽器并不會這么笨,它也是有做優(yōu)化的。它會把三次修改“保存”起來(大多數(shù)瀏覽器通過隊列化修改并批量執(zhí)行來優(yōu)化重排過程,也有設置時間片段的),一次完成!

然而,如果你在三行代碼中,以下獲取DOM布局信息。(為了返回最新的布局信息,將立即執(zhí)行渲染樹變化隊列的更新)

如上面被注釋的第4行,如果取消注釋會導致(2+3)、(5)兩次重排;

獲取關于DOM布局信息的屬性:

offsetTop, offsetLeft, offsetWidth, offsetHeight
scrollTop, scrollLeft, scrollWidth, scrollHeight
clientTop, clientLeft, clientWidth, clientHeight
getComputedStyle() (currentStyle in IE)

 

4 應對方法:盡量減少重繪次數(shù)、減少重排次數(shù)、縮小重排的影響范圍。

4.1 合并多次操作,如上面的操作

ele.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px;';

4.2 將需要多次重排的元素,position屬性設為absolute或fixed,這樣此元素就脫離了文檔流,它的變化不會影響到其他元素。例如有動畫效果的元素就最好設置為絕對定位。

4.3 由于display屬性為none的元素不在渲染樹中,對隱藏的元素操作不會引發(fā)其他元素的重排。如果要對一個元素進行復雜的操作時,可以先隱藏它,操作完成后再顯示。這樣只在隱藏和顯示時觸發(fā)2次重排。但是這可能導致瀏覽器的閃爍。

4.4 在內存中多次操作節(jié)點,完成后再添加到文檔中去(可使用fragment元素)。例如要異步獲取表格數(shù)據,渲染到頁面??梢韵热〉脭?shù)據后在內存中構建整個表格的html片段,再一次性添加到文檔中去,而不是循環(huán)添加每一行。

var fragment = document.createDocumentFragment();  // 未使用的虛擬節(jié)點,appendChild(fragment) //append的是里面的子元素
 
var li = document.createElement('li');
li.innerHTML = 'apple';
fragment.appendChild(li);
 
var li = document.createElement('li');
li.innerHTML = 'watermelon';
fragment.appendChild(li);
 
document.getElementById('fruit').appendChild(fragment);

以上就是小編為大家?guī)淼臏\談DOM的操作以及性能優(yōu)化問題-重繪重排全部內容了,希望大家多多支持腳本之家~

相關文章

  • JavaScript的parseInt 進制問題

    JavaScript的parseInt 進制問題

    今天在整理以前寫過的一段根據周期值自動計算下次執(zhí)行日期的js代碼,發(fā)現(xiàn)一bug,我使用parseInt對源數(shù)據串進行轉換,當輸入類似:2009-05-05時,parseInt將把串的05做8進制轉換,這樣結果自然就不對了。
    2009-05-05
  • JS拉起或下載app的實現(xiàn)代碼

    JS拉起或下載app的實現(xiàn)代碼

    最近做項目遇到這樣的需求,通過手機網頁判斷是否安裝了自己公司app,如果安裝了則拉起app,沒有安裝則跳轉到下載頁。怎么實現(xiàn)呢?下面小編給大家分享js拉起或下載app的實現(xiàn)代碼,需要的朋友參考下
    2017-02-02
  • 詳解js的事件代理(委托)

    詳解js的事件代理(委托)

    JavaScript事件代理(委托)一般用于以下情況:1. 事件注冊在祖先級元素上,代理其子級元素。可以減少事件注冊數(shù)量,節(jié)約內存開銷,提高性能。2. 對js動態(tài)添加的子元素可自動綁定事件。本文主要介紹用原生 js 實現(xiàn)該功能。下面跟著小編一起來看下吧
    2016-12-12
  • 原生JS封裝ajax 傳json,str,excel文件上傳提交表單(推薦)

    原生JS封裝ajax 傳json,str,excel文件上傳提交表單(推薦)

    這篇文章主要介紹了原生JS封裝ajax 傳json,str,excel文件上傳提交表單(推薦)的相關資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-06-06
  • js隨機密碼產生函數(shù)

    js隨機密碼產生函數(shù)

    在網上找了好多隨機產生的密碼的代碼,沒一個好用的,所以就隨便寫了一個
    2010-08-08
  • 值得分享的最全面Bootstrap快速人門案例

    值得分享的最全面Bootstrap快速人門案例

    這篇文章主要為大家詳細介紹了最全面的前端插件Bootstrap快速人門案例,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • 楊氏矩陣查找的JS代碼

    楊氏矩陣查找的JS代碼

    楊氏矩陣查找的JS代碼,需要的朋友可以參考一下
    2013-03-03
  • 動態(tài)加載外部javascript文件的函數(shù)代碼分享

    動態(tài)加載外部javascript文件的函數(shù)代碼分享

    動態(tài)加載外部javascript文件的函數(shù)代碼分享,做個記錄備忘,方便查找。
    2011-07-07
  • 移動端(微信等使用vConsole調試console的方法

    移動端(微信等使用vConsole調試console的方法

    這篇文章主要介紹了移動端(微信等使用vConsole調試console的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • ES6中Promise的使用方法實例總結

    ES6中Promise的使用方法實例總結

    這篇文章主要介紹了ES6中Promise的使用方法,結合實例形式總結分析了Promise對象中的各種常用方法及基本使用技巧,需要的朋友可以參考下
    2020-02-02

最新評論