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.