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

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

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

寫在前面:

大家都知道DOM的操作很昂貴?!?/p>

然后貴在什么地方呢?

一、訪問DOM元素

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

一、訪問DOM  

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

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

// code1錯(cuò)誤
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集合。這個(gè)集合是實(shí)時(shí)更新的,即后面代碼修改了DOM,會(huì)反映在這個(gè)html集合里面??蓢L試代碼。


<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>


正因?yàn)檫@個(gè)原因:html集合,讀取 length 屬性比數(shù)組消耗大多了。

要解決這個(gè)問題并不難,在遍歷DOM集合的時(shí)候,緩存length就好了。不要每次使用就獲取,主要體現(xiàn)在for循環(huán)中(你應(yīng)該知道,for循環(huán)中,每一次都會(huì)執(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標(biāo)記、JavaScript、CSS、圖片之后會(huì)解析生成兩個(gè)內(nèi)部數(shù)據(jù)結(jié)構(gòu)——DOM樹和渲染樹。

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

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

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

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

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

2.1 修改DOM元素幾何屬性:

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

2.2 DOM樹結(jié)構(gòu)發(fā)生變化

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

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

3.渲染樹變化的排隊(duì)和刷新

思考下面代碼:

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

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

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

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

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

獲取關(guān)于DOM布局信息的屬性:

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

 

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

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

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

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

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

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

var fragment = document.createDocumentFragment();  // 未使用的虛擬節(jié)點(diǎn),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)化問題-重繪重排全部內(nèi)容了,希望大家多多支持腳本之家~

相關(guān)文章

  • JavaScript的parseInt 進(jìn)制問題

    JavaScript的parseInt 進(jìn)制問題

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

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

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

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

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

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

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

    js隨機(jī)密碼產(chǎn)生函數(shù)

    在網(wǎng)上找了好多隨機(jī)產(chǎn)生的密碼的代碼,沒一個(gè)好用的,所以就隨便寫了一個(gè)
    2010-08-08
  • 值得分享的最全面Bootstrap快速人門案例

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

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

    楊氏矩陣查找的JS代碼

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

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

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

    移動(dòng)端(微信等使用vConsole調(diào)試console的方法

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

    ES6中Promise的使用方法實(shí)例總結(jié)

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

最新評論