<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    瘋狂

    STANDING ON THE SHOULDERS OF GIANTS
    posts - 481, comments - 486, trackbacks - 0, articles - 1
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    加速Javascript:DOM操作優(yōu)化

    Posted on 2010-10-17 23:53 瘋狂 閱讀(548) 評論(0)  編輯  收藏 所屬分類: java java性能web方法論

    原文:《Speeding up JavaScript: Working with the DOM》

    作者: KeeKim Heng, Google Web Developer

    在我們開發(fā)互聯(lián)網(wǎng)富應(yīng)用(RIA)時(shí),我們經(jīng)常寫一些javascript腳本來修改或者增加頁面元素,這些工作最終是DOM——或者說文檔對象模型——來完成的,而我們的實(shí)現(xiàn)方式會影響到應(yīng)用的響應(yīng)速度。

    DOM操作會導(dǎo)致瀏覽器重解析(reflow),這是瀏覽器的一個(gè)決定頁面元素如何展現(xiàn)的計(jì)算過程。直接修改DOM,修改元素的CSS樣式,修改瀏覽器的窗口大小,都會觸發(fā)重解析。讀取元素的布局屬性比如offsetHeithe或者offsetWidth也會觸發(fā)重解析。重解析需要花費(fèi)計(jì)算時(shí)間,因此重解析觸發(fā)的越少,應(yīng)用就會越快。

    DOM操作通常要不就是修改已經(jīng)存在的頁面上的元素,要不就是創(chuàng)建新的頁面元素。下面的4種優(yōu)化方案覆蓋了修改和創(chuàng)建DOM節(jié)點(diǎn)兩種方式,幫助你減少觸發(fā)瀏覽器重解析的次數(shù)。

    方案一:通過CSS類名切換來修改DOM

     

    這個(gè)方案讓我們可以一次性修改一個(gè)元素和它的子元素的多個(gè)樣式屬性而只觸發(fā)一次重解析。

    需求:

    (emu注:原文作者寫到這里的時(shí)候腦子顯然短路了一下,把后面的Out-of-the-flow DOM Manipulation模式要解決的問題給擺到這里來了,不過從示范代碼中很容易明白作者真正想描述的問題,因此emu就不照翻原文了)

    我們現(xiàn)在需要寫一個(gè)函數(shù)來修改一個(gè)超鏈接的幾個(gè)樣式規(guī)則。要實(shí)現(xiàn)很簡單,把這幾個(gè)規(guī)則對應(yīng)的屬性逐一改了就好了。但是帶來的問題是,每修改一個(gè)樣式屬性,都會導(dǎo)致一次頁面的重解析。

    view plaincopy to clipboardprint?
    function selectAnchor(element) {  
      element.style.fontWeight = 'bold';  
      element.style.textDecoration = 'none';  
      element.style.color = '#000';  

    function selectAnchor(element) {
      element.style.fontWeight = 'bold';
      element.style.textDecoration = 'none';
      element.style.color = '#000';
    }

    解決方案

    要解決這個(gè)問題,我們可以先創(chuàng)建一個(gè)樣式名,并且把要修改的樣式規(guī)則都放到這個(gè)類名上,然后我們給超鏈接添加上這個(gè)新類名,就可以實(shí)現(xiàn)添加幾個(gè)樣式規(guī)則而只觸發(fā)一次重解析了。這個(gè)模式還有個(gè)好處是也實(shí)現(xiàn)了表現(xiàn)和邏輯相分離。

    view plaincopy to clipboardprint?
    .selectedAnchor {  
      font-weight: bold;  
      text-decoration: none;  
      color: #000;  
    }  
     
    function selectAnchor(element) {  
      element.className = 'selectedAnchor';  

    .selectedAnchor {
      font-weight: bold;
      text-decoration: none;
      color: #000;
    }

    function selectAnchor(element) {
      element.className = 'selectedAnchor';
    }

     方案二:在非渲染區(qū)修改DOM

    (emu注:作者在這里再次腦子短路,把DocumentFragment DOM Generation模式的介紹提前到這里來了,emu只好再次發(fā)揮一下)
    上一個(gè)方案解決的是修改一個(gè)超鏈接的問題,當(dāng)一次需要對很多個(gè)超鏈接進(jìn)行相同修改的時(shí)候,這個(gè)方案就可以大顯身手了。

    需求

    需求是這樣的,我們要寫一個(gè)函數(shù)來修改一個(gè)指定元素的子元素中所有的超鏈接的樣式名(className)屬性。要實(shí)現(xiàn)很簡單,我們可以通過遍歷每個(gè)超鏈接并且修改它們的樣式名來完成任務(wù)。但是帶來的問題就是,每修改一個(gè)超鏈接都會導(dǎo)致一次重解析。

    view plaincopy to clipboardprint?
    function updateAllAnchors(element, anchorClass) {  
      var anchors = element.getElementsByTagName('a');  
      for (var i = 0, length = anchors.length; i < length; i ++) {  
        anchors[i].className = anchorClass;  
      }  

    function updateAllAnchors(element, anchorClass) {
      var anchors = element.getElementsByTagName('a');
      for (var i = 0, length = anchors.length; i < length; i ++) {
        anchors[i].className = anchorClass;
      }
    }
     

    解決方案

    要解決這個(gè)問題,我們可以把被修改的指定元素從DOM里面移除,再修改所有的超鏈接,然后在把這個(gè)元素插入回到它原來的位置上。為了完成這個(gè)復(fù)雜的操作,我們可以先寫一個(gè)可重用的函數(shù),它不但移除了這個(gè)DOM節(jié)點(diǎn),還返回了一個(gè)把元素插回到原來的位置的函數(shù)。

    view plaincopy to clipboardprint?
    /** 
     * Remove an element and provide a function that inserts it into its original position 
     * @param element {Element} The element to be temporarily removed 
     * @return {Function} A function that inserts the element into its original position 
     **/ 
    function removeToInsertLater(element) {  
      var parentNode = element.parentNode;  
      var nextSibling = element.nextSibling;  
      parentNode.removeChild(element);  
      return function() {  
        if (nextSibling) {  
          parentNode.insertBefore(element, nextSibling);  
        } else {  
          parentNode.appendChild(element);  
        }  
      };  

    /**
     * Remove an element and provide a function that inserts it into its original position
     * @param element {Element} The element to be temporarily removed
     * @return {Function} A function that inserts the element into its original position
     **/
    function removeToInsertLater(element) {
      var parentNode = element.parentNode;
      var nextSibling = element.nextSibling;
      parentNode.removeChild(element);
      return function() {
        if (nextSibling) {
          parentNode.insertBefore(element, nextSibling);
        } else {
          parentNode.appendChild(element);
        }
      };
    }

    有了上面這個(gè)函數(shù),現(xiàn)在我們就可以在一個(gè)不需要解析渲染的元素上面修改那些超鏈接了。這樣只在移除和插入元素的時(shí)候各觸發(fā)一次重解析。

    view plaincopy to clipboardprint?
    function updateAllAnchors(element, anchorClass) {  
      var insertFunction = removeToInsertLater(element);  
      var anchors = element.getElementsByTagName('a');  
      for (var i = 0, length = anchors.length; i < length; i ++) {  
        anchors[i].className = anchorClass;  
      }  
      insertFunction();  

    function updateAllAnchors(element, anchorClass) {
      var insertFunction = removeToInsertLater(element);
      var anchors = element.getElementsByTagName('a');
      for (var i = 0, length = anchors.length; i < length; i ++) {
        anchors[i].className = anchorClass;
      }
      insertFunction();
    }
     

    方案三:一次性的DOM元素生成

    這個(gè)方案讓我們創(chuàng)建一個(gè)元素的過程只觸發(fā)一次重解析。在創(chuàng)建完元素以后,先進(jìn)行所有需要的修改,最后才把它插入到DOM里面去就可以了

    需求

    需求是這樣的,實(shí)現(xiàn)一個(gè)函數(shù),往一個(gè)指定的父元素上插入一個(gè)超鏈接元素。這個(gè)函數(shù)要同時(shí)可以設(shè)置這個(gè)超鏈接的顯示文字和樣式類。我們可以這樣做:創(chuàng)建元素,插入到DOM里面,然后設(shè)置相應(yīng)的屬性。這就要觸發(fā)3次重解析。

    view plaincopy to clipboardprint?
    function addAnchor(parentElement, anchorText, anchorClass) {  
      var element = document.createElement('a');  
      parentElement.appendChild(element);  
      element.innerHTML = anchorText;  
      element.className = anchorClass;  

    function addAnchor(parentElement, anchorText, anchorClass) {
      var element = document.createElement('a');
      parentElement.appendChild(element);
      element.innerHTML = anchorText;
      element.className = anchorClass;
    }
     

    解決方案

    很簡單,我們只要把插入元素這個(gè)操作放到最后做,就可以只進(jìn)行一次重解析了。

    view plaincopy to clipboardprint?
    function addAnchor(parentElement, anchorText, anchorClass) {  
      var element = document.createElement('a');  
      element.innerHTML = anchorText;  
      element.className = anchorClass;  
      parentElement.appendChild(element);  

    function addAnchor(parentElement, anchorText, anchorClass) {
      var element = document.createElement('a');
      element.innerHTML = anchorText;
      element.className = anchorClass;
      parentElement.appendChild(element);
    }

    不過,要是我們想要插入很多個(gè)超鏈接到一個(gè)元素里面的話,那么這個(gè)做法還是有問題:每插入一個(gè)超鏈接還是要觸發(fā)一次重解析。下一個(gè)方案可以解決這個(gè)問題。

    方案四:通過文檔片段對象(DocumentFragment)創(chuàng)建一組元素

    這個(gè)方案允許我們創(chuàng)建并插入很多個(gè)元素而只觸發(fā)一次重解析。要實(shí)現(xiàn)這點(diǎn)需要用到所謂的文檔片段對象(DocumentFragment)。我們先在DOM之外創(chuàng)建一個(gè)文檔片段對象(這樣它也就不需要解析和渲染),然后我們在文檔片段對象中創(chuàng)建很多個(gè)元素,最后我們把這個(gè)文檔片段對象中所有的元素一次性放到DOM里面去,只觸發(fā)一次重解析。

    需求


    我們要寫一個(gè)函數(shù),往一個(gè)指定的元素上面增加10個(gè)超鏈接。如果我們簡單的直接插入10個(gè)超鏈接到元素上面,就會觸發(fā)10次重解析。

    view plaincopy to clipboardprint?
    function addAnchors(element) {  
      var anchor;  
      for (var i = 0; i < 10; i ++) {  
        anchor = document.createElement('a');  
        anchor.innerHTML = 'test';  
        element.appendChild(anchor);  
      }  

    function addAnchors(element) {
      var anchor;
      for (var i = 0; i < 10; i ++) {
        anchor = document.createElement('a');
        anchor.innerHTML = 'test';
        element.appendChild(anchor);
      }
    }

    解決方案

    要解決這個(gè)問題,我們要先創(chuàng)建一個(gè)文檔片段對象,然后把每個(gè)新創(chuàng)建的超鏈接都插入到它里面去。當(dāng)我們把文檔片段對象用appendChild命令插入到指定的節(jié)點(diǎn)時(shí),這個(gè)文檔片段對象的所有子節(jié)點(diǎn)就一起被插入到指定的元素里面,而且只需要觸發(fā)一次重解析。

    view plaincopy to clipboardprint?
    function addAnchors(element) {  
      var anchor, fragment = document.createDocumentFragment();  
      for (var i = 0; i < 10; i ++) {  
        anchor = document.createElement('a');  
        anchor.innerHTML = 'test';  
        fragment.appendChild(anchor);  
      }  
      element.appendChild(fragment);  

     

    本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/emu/archive/2010/03/01/5334583.aspx

    主站蜘蛛池模板: 亚洲中文无码永久免费 | 免费在线人人电影网| 免费国产成人午夜私人影视| 老司机福利在线免费观看| 亚洲第一精品在线视频| 久久精品国产亚洲网站| 69影院毛片免费观看视频在线| 亚洲av日韩专区在线观看| 亚洲一区二区三区在线视频| 亚洲一级毛片免费观看| 羞羞视频免费网站入口| 91精品国产亚洲爽啪在线观看| 国产精品嫩草影院免费| 未满十八18禁止免费无码网站 | 在线观看国产区亚洲一区成人 | 亚洲女初尝黑人巨高清| AV免费网址在线观看| 国产美女视频免费观看的网站 | 亚洲明星合成图综合区在线| 国产人妖ts在线观看免费视频| 日韩精品免费视频| 美女一级毛片免费观看| 久久精品亚洲精品国产色婷 | 在线不卡免费视频| 日韩精品免费在线视频| 美女扒开尿口给男人爽免费视频| 亚洲三级电影网站| 国产综合亚洲专区在线| 免费高清在线爱做视频| 57pao国产成永久免费视频| av午夜福利一片免费看久久| 亚洲色图激情文学| 亚洲白色白色永久观看| 亚洲人成亚洲人成在线观看| 国产免费av一区二区三区| 99在线精品视频观看免费| 久久免费高清视频| kk4kk免费视频毛片| 色偷偷亚洲男人天堂| 亚洲精品亚洲人成在线播放| 亚洲人成电影亚洲人成9999网 |