JavaScript: document.getElementById медленная производительность?

Я многократно использую document.getElementById в общих CSS-элементах.

Будет ли значительное увеличение производительности, если я создам 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"
...

Ответы

Ответ 1

Итак, все ответы "да" меня прослушивали, поэтому я на самом деле приурочил это к тому, чтобы getElementById был медленным!

Вот результаты (для страницы с 10000 элементами на ней):

IE8 getElementById: 0.4844 ms
Поиск массива идентификаторов IE8: 0,0062 мс

Chrome getElementById: 0.0039 ms
Поиск массива id: 0.0006 мс

Firefox 3.5 был сопоставим с хром.

Половина миллисекунды за вызов функции не заставит меня использовать массив;) Но, возможно, это хуже на IE6, который я не установил.

Здесь мой script:

<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>

Ответ 2

Поскольку вы говорите "элементы CSS", я подозреваю, что большая часть вашей медленной производительности связана не с повторяющимся использованием document.getElementById() (чего вам следует избегать в любом случае), а сколько раз вы изменяете объект style для с учетом node.

Каждый раз, когда вы изменяете свойство на style, вы заставляете браузер повторно рисовать этот элемент и, возможно, многие другие на странице.

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

Здесь лучшее решение - использовать классы CSS и переключать или добавлять/удалять имя класса из node. Это позволяет вам вставлять столько изменений стиля, сколько вы хотите, за счет только одного повторного розыгрыша.

var elem = document.getElementById( 'desc' );
elem.className = "whatever"; // Only one browser re-draw!

Ответ 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]);
}

Ответ 4

Да!

Недавно была ситуация, когда я получал малоэффективные элементы, изменяющие производительность. Решение заключалось в создании словаря, такого как ваш пример. Я буквально улучшил производительность в 1000 раз (по крайней мере, в IE6).

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

Ответ 5

Зависит от определения "значительного". Доступ к массиву GlobalElementId.asc намного быстрее, чем вызов getElementById(). Но getElementById все еще очень быстро по сравнению с большинством других манипуляций с DOM, которые, вероятно, будут выполняться script, и, по всей вероятности, это всего лишь очень малая часть вашего времени выполнения script.

Сначала я напишу для удобства чтения, для которого ответ Soufiane будет казаться лучшим. Только если на практике эта часть script оказалась слишком медленной, я бы начал думать о кэшах поиска, которые добавляют дополнительную сложность (особенно если вы начнете изменять эти элементы во время выполнения).

Боковое примечание: не используйте setAttribute, он прослушивается в IE и менее читабельен, чем просто использует свойства HTML DOM уровня 1, такие как element.href= '...';.

Ответ 6

Короткий ответ - да, в любое время вы можете сделать переменную Javascript или ссылку на объект локальной, это поможет с производительностью.

Если вы хотите более глубокое понимание управления областью и ее последствий для производительности на Javascript, Speed ​​Up Your Javascript, есть действительно хорошая информация. Очень рекомендуемый просмотр.

Ответ 7

Да, но использование массива переусердствует.

См. ответ Soufiane Hassou о том, как это сделать.

Ответ 8

Его называемое кэширование объектов и повысит производительность script.
Подробнее см. http://www.javascriptkit.com/javatutors/efficientjs.shtml.
Кроме того, если вы часто меняете CSS, я бы предложил использовать jQuery, как было предложено @Fahad.

Ответ 9

Нет, не будет значительного увеличения производительности. Проблемы с производительностью лежат в другом месте. У браузера есть свой собственный индекс на элементе id → element object.

Если вы хотите узнать, почему ваш код медленный, очень важно время, потому что медленная часть, вероятно, не то, что вы ожидаете (я нашел это из-за трудного пути). Вы можете сделать это следующим образом:

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

Хотя важно отметить, что точность здесь составляет 15 мс, а это означает, что если что-то занимает 14 мс, в некоторых браузерах оно может отображаться как 0 мс.

Вот как выглядит ваш код в jQuery:

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

Ответ 10

В браузерах IE ответ ДА!

Я сделал контрольную отметку (похожую на Майка Блэндфорда) и выяснил, что когда вы вызываете document.getElementById() в браузере IE, он обходит DOM, пока не найдет элемент с желаемым идентификатором, вместо того, чтобы хранить карту/хеш-таблицу id-to-element. (ужасно, я знаю).

Таким образом, создание массива, как вы предложили, будет улучшением производительности EXTREME.