JavaScript:document.getElementById性能下降?

时间:2009-11-11 16:17:33

标签: javascript optimization

我在常见 CSS元素上重复使用document.getElementById

如果我创建global array来存储我的所有document.getElementById元素而不是每次都重新获取元素,会不会有显着的性能提升?

示例,而不是:

document.getElementById("desc").setAttribute("href", "#");
document.getElementById("desc").onclick = function() {...};
document.getElementById("desc").style.textDecoration = "none"
document.getElementById("asc").setAttribute("href", "#");
document.getElementById("asc").onclick = function() {...};
document.getElementById("asc").style.textDecoration = "none"
...

简单地做:

var GlobalElementId = [];
GlobalElementId ["desc"] = document.getElementById("desc");
GlobalElementId ["asc"] = document.getElementById("asc");
GlobalElementId [...] = document.getElementById(...);

GlobalElementId ["desc"].setAttribute("href", "#");
GlobalElementId ["desc"].onclick = function() {...};
GlobalElementId ["desc"].style.textDecoration = "none"
...

10 个答案:

答案 0 :(得分:21)

所以所有“是”的答案都在困扰我,所以我实际上计时了,看看getElementById是否很慢!

以下是结果(表示包含10,000个元素的页面):

IE8 getElementById:0.4844 ms
IE8 id数组查找:0.0062 ms

Chrome getElementById:0.0039 ms
Chrome ID阵列查找:0.0006 ms

Firefox 3.5与chrome相当。

每个函数调用半毫秒不会让我使用数组;) 但也许它在IE6上更糟糕,我还没有安装。

这是我的剧本:

<html>
<head>
<script type="text/javascript">
    var numEles = 10000;
    var idx = {};

    function test(){
        generateElements();
        var t0 = (new Date()).getTime();
        var x = selectElementsById();
        var t1 = (new Date()).getTime();
        var time = t1 - t0;
        generateIndex();
        var t2 = (new Date()).getTime();
        var x = selectElementsWithIndex();
        var t3 = (new Date()).getTime();
        var idxTime = t3 - t2;

        var msg = "getElementById time = " + (time / numEles) + " ms (for one call)\n"
            + "Index Time = " + (idxTime/ numEles) + " ms (for one call)";
        alert(msg);
    }

    function generateElements(){
        var d = document.getElementById("mainDiv");
        var str = [];
       for(var i=0;i<numEles;i++){
           str.push("<div id='d_" + i + "' >" + i + "</div>");
        }
        d.innerHTML = str.join('');
    }

    function selectElementsById(){
        var eles = [];
        for(var i=0;i<numEles;i++){
            var id = ((i * 99) % numEles);
            eles.push(document.getElementById("d_" + id));
        }
        return eles;
    }

    function generateIndex(){
        for(var i=0;i<numEles;i++){
            var id = "d_" + i;
           idx[id] = document.getElementById(id);
        }
    }

    function selectElementsWithIndex(){
        var eles = [];
        for(var i=0;i<numEles;i++){
            var id = ((i * 99) % numEles);
            eles.push(idx["d_" + id]);
        }
        return eles;
    }   
</script>
</head>
<body onload="javascript:test();" >
<div id="mainDiv" />
</body>
</html>

答案 1 :(得分:7)

既然你说“CSS元素”我怀疑你的很多性能不是因为重复使用document.getElementById()(你应该避免使用),而是你修改{{1}的次数对象为给定节点。

每次更改style上的属性时,都会强制浏览器重新绘制该元素,可能还会重新绘制页面上的其他元素。

style

这里,更好的解决方案是使用CSS类并从节点切换或添加/删除类名。这样,您只需一次重新绘制即可打包所需的样式更改。

var elem = document.getElementById( 'desc' );
elem.style.textDecoration = "none"; // browser re-draw
elem.style.borderWidth    = "2px";  // browser re-draw
elem.style.paddingBottom  = "5px";  // browser re-draw

答案 2 :(得分:3)

对我来说,这样做更合适,更有利于表现:

var desc = document.getElementById("desc");
var asc = document.getElementById("asc");
desc.setAttribute("href","#");
asc.onclick = function() { ... }
...

在重新考虑ChaosPandion所说的话之后,我认为有一种方法可以做到:

var elements = ["desc", "asc", ...];
for(var i = 0; i < elements.length; i++) {
  GlobalElementId[elements[i]] = document.getElementById(elements[i]);
}

答案 3 :(得分:2)

是!

不久前有一种情况我在修改元素时表现不佳。 解决方案是像你的例子一样建立一个字典。我的性能提升了1000倍(至少在IE6中)。

var elementCache = {};
function buildElementCache() {
    elementCache[id] = {
        element1: document.getElementById(id + "1"),
        element2: document.getElementById(id + "2")
    } 
    // Etc...   
}

答案 4 :(得分:1)

取决于'重要'的定义。 GlobalElementId.asc数组访问比getElementById()调用的速度快得多。但是,与你的脚本可能正在进行的大多数其他DOM操作相比,getElementById仍然非常快,并且很可能只是脚本执行时间的一小部分。

我首先为可读性而写,Soufiane的答案看起来最好。只有在实践中脚本部分被证明太慢才会开始考虑查找缓存,这会增加额外的复杂性(特别是如果你在运行时开始更改这些元素)。

附注:不要使用setAttribute,它在IE中被窃听,并且不如仅使用像element.href= '...';这样的DOM Level 1 HTML属性。

答案 5 :(得分:1)

简短的回答是肯定的,任何时候你可以将Javascript变量或对象引用到本地,这将有助于提高性能。

如果您希望更深入地了解范围管理及其对Javascript的性能影响,Speed Up Your Javascript技术讲座有一些非常好的信息。强烈推荐观看。

答案 6 :(得分:0)

是的,但是使用数组会使它过度。

请参阅Soufiane Hassou关于如何做到的答案。

答案 7 :(得分:0)

它被称为对象缓存,它将提升你的脚本性能 有关详细信息,请参阅http://www.javascriptkit.com/javatutors/efficientjs.shtml 此外,如果您经常更改CSS,我建议使用@Fahad建议的jQuery。

答案 8 :(得分:0)

不,不会有显着的性能提升。你的表现问题在别处。浏览器在元素id上有自己的索引 - &gt;元素对象。

如果你想知道为什么你的代码很慢,那么定时它是非常重要的,因为缓慢的部分可能不是你所期望的(我发现这很难)。你可以这样做:

var t0 = (new Date()).getTime();
var t1 = (new Date()).getTime();
var time = t1 - t0;

虽然重要的是要注意这里的准确度是15ms,这意味着如果某些东西花了14ms,它可能会在某些浏览器中显示为0ms。

这是你的代码在jQuery中的样子:

$("#desc").attr("href", "#")
    .click(function(){})
    .css("text-decoration", "none");

答案 9 :(得分:0)

在IE浏览器中,答案是肯定的!

我做了一个基准测试(类似于Mike Blandford)并发现了这一点 当您在IE浏览器中调用document.getElementById()时,它会遍历DOM,直到找到具有所需id的元素,而不是保留id-to-element map / hashtable。 (可怕,我知道)。

因此,如您所提供的那样,创建一个数组将是一个非常好的性能提升。