JavaScript优化(二)

  • 访问和修改DOM元素
  • 修改DOM元素的样式会导致重绘(repaint)和重排(reflow)
  • 通过处理DOM事件处理与用户的交互

    DOM的访问与修改

    访问DOM元素是有代价的。修改元素则更为昂贵,因为它会导致浏览器重新计算页面的几何变化。

    为了让你对DOM编程带来的性能问题有个量化的了解,请看下面的实例:


    function innerHTMLLoop() {
        for (var count = 0; count < 15000; count++) {
            document.getElementById('here').innerHTML += 'a';
        }
    }


    这个函数循环修改页面元素的内容。这段代码的问题在于,每次循环迭代,该元素都被访问两次:一次读取innerHTML属性值,另一次重写它。

    一个效率更高的版本是使用局部变量存储更新后的内容,然后再循环结束后一次性写入:


    function innerHTMLLoop2() {
        var content = '';
        for (var count = 0; count < 15000; count++) {
            content += 'a';
        }
        document.getElementById('here').innerHTML += content;
    }


    因此,一般经验法则:减少访问DOM的次数,把运算尽量留在ECMAScript这一端处理。


    节点克隆

    使用DOM方法更新页面内容的另一个途径是克隆已有元素,而不是创建新元素——换句话说,就是使用element.cloneNode()(element表示已有节点)替代document。createElement()。

    节点克隆提高效率不是特别明显。


    HTML集合

    HTML集合是包含了DOM节点引用的类数组对象。以下方法的返回值就是一个集合:


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


    事实上,HTML集合一直与文档保持着连接,每次你需要最新的信息时,都会重复执行查询的过程,哪怕只是获取集合里的元素的个数(即访问集合的length属性)也是如此。


    设置一个集合,并把它拷贝到一个数组中:

    var coll = document.getElementsByTagName('div');
    var ar = toArray(coll);

    比较下面两个函数:


    //较慢
    function loopCollection() {
        for (var count = 0; count < coll.length; count++) {

            /*代码处理*/
        }
    }


    // 较快
    function loopCopiedArray() {
        for (var count = 0; count < arr.length; count++) {

            /*代码处理*/
        }
    }


    在每次迭代过程中,读取元素集合的length属性会引发集合进行更新,这在所有浏览器中都有明显的性能问题。优化方法很简单,把集合的长度缓存到一个局部变量中,然后再循环的条件退出语句中使用该变量:

    function loopCacheLengthCollection() {
        var coll = document.getElementsByTagName('div'),
            len = coll.length;
        for (var count = 0; count < len; count++) {

            /*代码处理*/
        }
    }

    此函数运行速度和loopCopiedArray()一样快。


    访问集合元素时使用局部变量

    一般来说,对于任何类型的DOM访问,当同一个DOM属性或方法需要多次访问时,最好使用一个局部变量缓存此成员。当遍历一个集合时,首要优化原则是把集合存储在局部变量中,并把length缓存在循环外部,然后,使用局部变量访问这些需要多次访问的元素。

    例子:

    // 较慢
    function collectionGlobal() {

        var coll = document.getElementsByTagName('div'),
            len = coll.length,
            name = '';
        for (var count = 0; count < len; count++) {
            name = document.getElementsByTagName('div')[count].nodeName;
            name = document.getElementsByTagName('div')[count].nodeType;
            name = document.getElementsByTagName('div')[count].tagName;
        }
        return name;
    };


    // 较快
    function collectionLocal() {
        var coll = document.getElementsByTagName('div'),
            len = coll.length,
            name = '';
        for (var count = 0; count < len; count++) { 
            name = coll[count].nodeName;
            name = coll[count].nodeType;
            name = coll[count].tagName;
        }
        return name;
    };

    // 最快
    function collectionNodesLocal() {
        var coll = document.getElementsByTagName('div'),
            len = coll.length,
            name = '',
            el = null;
        for (var count = 0; count < len; count++) {
            el = coll[count];
            name = el.nodeName;
            name = el.nodeType;
            name = el.tagName;
        }
        return name;
    };


    选择器API

    考虑如下代码:

    var elements = document.querySelectorAll('#menu a');

    elements的值包含一个引用列表,指向位于id=“menu”的元素之间的所有a元素。querySelectorALL()方法使用CSS选择器作为参数并返回一个NodeList——包含着匹配节点的类数组对象。这个方法不会返回HTML集合,因此返回的节点不会对应实时的文档结构。


    如果不使用querySelectorAll(),为了达到相同目的,代码要冗长一些:

    var elements = document.getElementById('menu').getElementsByTagName('a');

    这种情况下,elements会是一个HTML集合,所以还需要把它拷贝到一个数组中,才能达到与querySelectorAll()返回值类似的静态列表。

    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值