兩種方式實(shí)現(xiàn)加速Javascript DOM操作優(yōu)化
你對(duì)加速Javascript DOM操作優(yōu)化的方法是否熟悉,在我們開(kāi)發(fā)互聯(lián)網(wǎng)富應(yīng)用(RIA)時(shí),我們經(jīng)常寫(xiě)一些javascript腳本來(lái)修改或者增加頁(yè)面元素,這些工作最終是DOM——或者說(shuō)文檔對(duì)象模型——來(lái)完成的,而我們的實(shí)現(xiàn)方式會(huì)影響到應(yīng)用的響應(yīng)速度。
加速Javascript DOM操作優(yōu)化
在我們開(kāi)發(fā)互聯(lián)網(wǎng)富應(yīng)用(RIA)時(shí),我們經(jīng)常寫(xiě)一些javascript腳本來(lái)修改或者增加頁(yè)面元素,這些工作最終是DOM——或者說(shuō)文檔對(duì)象模型——來(lái)完成的,而我們的實(shí)現(xiàn)方式會(huì)影響到應(yīng)用的響應(yīng)速度。
Javascript DOM操作會(huì)導(dǎo)致瀏覽器重解析(reflow),這是瀏覽器的一個(gè)決定頁(yè)面元素如何展現(xiàn)的計(jì)算過(guò)程。直接修改DOM,修改元素的CSS樣式,修改瀏覽器的窗口大小,都會(huì)觸發(fā)重解析。讀取元素的布局屬性比如offsetHeithe或者offsetWidth也會(huì)觸發(fā)重解析。重解析需要花費(fèi)計(jì)算時(shí)間,因此重解析觸發(fā)的越少,應(yīng)用就會(huì)越快。
Javascript DOM操作通常要不就是修改已經(jīng)存在的頁(yè)面上的元素,要不就是創(chuàng)建新的頁(yè)面元素。下面有兩種優(yōu)化方案,大致覆蓋了修改和創(chuàng)建DOM節(jié)點(diǎn)兩種方式,幫助你減少觸發(fā)瀏覽器重解析的次數(shù)。
方案一:通過(guò)CSS類(lèi)名切換來(lái)修改DOM
這個(gè)方案讓我們可以一次性修改一個(gè)元素和它的子元素的多個(gè)樣式屬性而只觸發(fā)一次重解析。
需求:
(emu注:原文作者寫(xiě)到這里的時(shí)候腦子顯然短路了一下,把后面的Out-of-the-flowDOMManipulation模式要解決的問(wèn)題給擺到這里來(lái)了,不過(guò)從示范代碼中很容易明白作者真正想描述的問(wèn)題,因此emu就不照翻原文了)
我們現(xiàn)在需要寫(xiě)一個(gè)函數(shù)來(lái)修改一個(gè)超鏈接的幾個(gè)樣式規(guī)則。要實(shí)現(xiàn)很簡(jiǎn)單,把這幾個(gè)規(guī)則對(duì)應(yīng)的屬性逐一改了就好了。但是帶來(lái)的問(wèn)題是,每修改一個(gè)樣式屬性,都會(huì)導(dǎo)致一次頁(yè)面的重解析。
- functionselectAnchor(element){
 - element.style.fontWeight='bold';
 - element.style.textDecoration='none';
 - element.style.color='#000';
 - }
 
解決方案:
要解決這個(gè)問(wèn)題,我們可以先創(chuàng)建一個(gè)樣式名,并且把要修改的樣式規(guī)則都放到這個(gè)類(lèi)名上,然后我們給超鏈接添加上這個(gè)新類(lèi)名,就可以實(shí)現(xiàn)添加幾個(gè)樣式規(guī)則而只觸發(fā)一次重解析了。這個(gè)模式還有個(gè)好處是也實(shí)現(xiàn)了表現(xiàn)和邏輯相分離。
- .selectedAnchor{
 - font-weight:bold;
 - text-decoration:none;
 - color:#000;
 - }
 - functionselectAnchor(element){
 - element.className='selectedAnchor';
 - }
 
介紹了加速Javascript DOM操作優(yōu)化的方案一,下面來(lái)看一下方案二。#p#
方案二:在非渲染區(qū)修改DOM
(emu注:作者在這里再次腦子短路,把DocumentFragmentDOMGeneration模式的介紹提前到這里來(lái)了,emu只好再次發(fā)揮一下)
上一個(gè)方案解決的是修改一個(gè)超鏈接的問(wèn)題,當(dāng)一次需要對(duì)很多個(gè)超鏈接進(jìn)行相同修改的時(shí)候,這個(gè)方案就可以大顯身手了。
需求:
需求是這樣的,我們要寫(xiě)一個(gè)函數(shù)來(lái)修改一個(gè)指定元素的子元素中所有的超鏈接的樣式名(className)屬性。要實(shí)現(xiàn)很簡(jiǎn)單,我們可以通過(guò)遍歷每個(gè)超鏈接并且修改它們的樣式名來(lái)完成任務(wù)。但是帶來(lái)的問(wèn)題就是,每修改一個(gè)超鏈接都會(huì)導(dǎo)致一次重解析。
- functionupdateAllAnchors(element,anchorClass){
 - varanchors=element.getElementsByTagName('a');
 - for(vari=0,length=anchors.length;i<length;i++){
 - anchors[i].className=anchorClass;
 - }
 - }
 
解決方案:
要解決這個(gè)問(wèn)題,我們可以把被修改的指定元素從DOM里面移除,再修改所有的超鏈接,然后在把這個(gè)元素插入回到它原來(lái)的位置上。為了完成這個(gè)復(fù)雜的操作,我們可以先寫(xiě)一個(gè)可重用的函數(shù),它不但移除了這個(gè)DOM節(jié)點(diǎn),還返回了一個(gè)把元素插回到原來(lái)的位置的函數(shù)。
- /**
 - *Removeanelementandprovideafunction
 - thatinsertsitintoitsoriginalposition
 - *@paramelement{Element}Theelementtobetemporarilyremoved
 - *@return{Function}Afunctionthatinsertstheelementintoitsoriginalposition
 - **/
 - functionremoveToInsertLater(element){
 - varparentNode=element.parentNode;
 - varnextSibling=element.nextSibling;
 - parentNode.removeChild(element);
 - returnfunction(){
 - if(nextSibling){
 - parentNode.insertBefore(element,nextSibling);
 - }else{
 - parentNode.appendChild(element);
 - }
 - };
 - }
 
有了上面這個(gè)函數(shù),現(xiàn)在我們就可以在一個(gè)不需要解析渲染的元素上面修改那些超鏈接了。這樣只在移除和插入元素的時(shí)候各觸發(fā)一次重解析。
- functionupdateAllAnchors(element,anchorClass){
 - varinsertFunction=removeToInsertLater(element);
 - varanchors=element.getElementsByTagName('a');
 - for(vari=0,length=anchors.length;i<length;i++){
 - anchors[i].className=anchorClass;
 - }
 - insertFunction();
 - }
 
【編輯推薦】
- 揭露JavaScript DOM操作基本原則
 - 減少瀏覽器重解析 JavaScript DOM操作優(yōu)化方案
 - JavaScript獲取HTML DOM節(jié)點(diǎn)元素詳解
 - JavaScript和DOM輕松實(shí)現(xiàn)數(shù)據(jù)訪問(wèn)
 - HTML DOM與XML DOM的區(qū)別與聯(lián)系探究
 















 
 
 



 
 
 
 