美文网首页
高性能javaScript(三)——DOM编程

高性能javaScript(三)——DOM编程

作者: 晓蟲QwQ | 来源:发表于2020-12-12 02:29 被阅读0次

访问和操作DOM是现代Web应用的重要部分。但每次穿越连接ECMAScript和DOM两个岛屿之间的桥梁,都会被收取“过桥费”。为了减少DOM编程带来的性能损失。

  • 最小化DOM访问次数,尽可能在JavaScript端处理。 (只适用于IE6之前的版本,新版本浏览器DOM方法更优)
 //多次调用DOM的API,不妥 
  function innerHTMLLoop() {
      for(var count = 0; count < 15000; count++) {
          document.getElementById('here').innerHTML += 'a';
      }
  }
  
 // 使用以下方法代替,只调用一次DOM的API,尽可能将在JavaScript端处理后再赋值 
  function innerHTMLLoop2() {
      var content = '';
      for(var count = 0; count < 15000; count++) {
          content += 'a';
      }
      document.getElementById('here').innerHTML += content;
  }
  • 使用节点克隆element.cloneNode()(element表示已有节点)比document.createElement()稍快。
  • 如果需要多次访问某个DOM节点,请使用局部变量存储它的引用。
  • 小心处理HTML集合,因为它实时联系着底层文档。把集合的长度缓存到一个变量中,并在迭代中使用它。如果需要经常操作集合,建议把它拷贝到一个数组中。

以下方法返回的是一个集合:

  • document.getElementsByName()
  • document.getElementsByClassName()
  • document.getElementsByTagName()

以下属性同样返回HTML集合

  • document.images
  • document.links
  • document.forms
  • document.forms[0].elements
  //以下代码会造成死循环,因为每次访问alldivs.length时都是实时的DOM信息
  var alldivs = document.getElementsByTagName('div');
  for(var i = 0; i < alldivs.length; i++) {
      document.body.appendChild(document.createElement('div'));
  }
  
  //将HTML集合拷贝到数组中使用
  function toArray(coll) {
      for(var i = 0,a = [],len = coll.length; i < len; i++) {
          a[i] = coll[i];
      }
      return a;
  }
  
  //访问集合的length比普通数组的length慢很多,所以也可以将集合的长度保存到变量中,用于循环判定
  function loopCacheLengthCollection() {
      var coll = document.getElementsByTagName('div'),
      len = coll.length;
      for(var count = 0; count < len; count++) {
          /* 代码处理 */
      }
  }

  • 如果可能的话,使用速度更快的API,比如querySelectorAll()和firstElementChild。

在老版本IE中nextSibling比childNode快。
老API不区分元素节点和其他节点,比如注释和文本节点。但在某些情况下只需访问元素节点,所以使用以下新API代替旧API

新属性名 被代替的属性
children childNodes
childElementCount childNodes.length
firstElementChild firstChild
lastElementChild lastChild
nextElementSibling nextSibling
previousElementSibling previousSibling
  • 要留意重绘和重排;批量修改样式时,“离线“操作DOM树,使用缓存,并减少访问布局信息的次数。

改变页面布局和几何属性会触发重排。但是浏览器一般会通过队列化修改并批量执行来优化重排。但是获取布局信息会导致队列刷新,如offsetTop,scrollTop,cilentTop等

批量修改DOM的方法:

  1. 使文档脱离文档流。
  2. 对其应用多重改变。
  3. 把元素带回文档中。

三种方法:

  • 隐藏元素,应用修改,重新显示。
  • 使用文档片段(document fragment)在当前DOM之外构建一个子树,再把它拷贝回文档。
  • 将原始元素拷贝到一个脱离文档的节点,修改副本,完成后再替换原始元素。
//更新指定节点数据的通用函数:
function appendDataToElement(appendToElement, data) {
    var a, li;
    for(var i = 0,max = data.length;i < max; i++) {
        a = document.createElement('a');
        a.href = data[i].url;
        a.appendChild(document.createTextNode(data[i].name));
        li = document.createElement('li');
        li.appendChild(a);
        appendDataToElement.appendChild(li);
    }
}

//第一种方法
var ul = document.getElementById('mylist');
ul.style.display = 'none';
appendDataToElement(ul,data);
ul.style.display = 'block';

//第二种方法,文档片段只会添加其内容而不会添加其本身。
var fragment = document.createDocumentFragment();
appendDataToElement(fragment,data);
document.getElementById('mylist').appendChild(fragment);

//第三种方案
var old = document.getElementById('mylist');
var clone = old.cloneNode(true);
appendDataToElement(clone,data);
old.parentNode.replaceChild(clone,old);
  • 动画中使用绝对定会,使用拖放代理。

使用以下步骤可以避免页面中的大部分重排:

  1. 使用绝对定位页面上的动画元素,将其脱离文档流。
  2. 让元素动起来。当它扩大时,会临时覆盖部分页面。但这只是页面一个小区域的重绘过程,不会产生重排并重绘页面大部分内容。
  3. 当动画结束时恢复定位,从而只会下移一次文档的其他元素。
  • 使用事件委托来减少事件处理器的数量。
//对li的父标签ul统一绑定事件委托
document.getElementById('menu').onclick = function(e) {
    // 浏览器target
    e = e || window.events;
    var target = e.target || e.srcElement;
    
    var pageid,hrefparts;
    
    //只关心hrefs,非链接点击则退出
    if(target.nodeName !== 'A') {
        return;
    }
    
    //从链接中找出页面ID
    hrefparts = target.href.split('/');
    pageid = hrefparts[hrefparts.length - 1];
    pageid = pageid.replace('.html','');
    
    //更新页面
    ajaxRequest('xhr.php?page=' + id, updatePageContents);
    
    //浏览器组织默认行为并取消冒泡
    if(typeof e.preventDefault === 'function') {
        e.preventDefault();
        e.stopPropagation();
    } else {
        e.returnValue = false;
        e.cancelBubble = true;
    }
}

相关文章

网友评论

      本文标题:高性能javaScript(三)——DOM编程

      本文链接:https://www.haomeiwen.com/subject/yyfegktx.html