Malheureusement, je dois parcourir tous les éléments DOM d'une page et je me demande quelle est la technique la plus efficace. Je pourrais probablement les comparer moi-même et le ferais si j'ai le temps, mais j'espère que quelqu'un a déjà vécu cela ou a des options que je n'avais pas envisagées.
actuellement j'utilise jQuery et je fais ça:
$('body *').each(function(){
var $this = $(this);
//do stuff
});
Bien que cela fonctionne, il semble provoquer un certain retard sur le client. Il pourrait également être modifié avec un contexte jQuery plus spécifique comme $('body', '*')
Il m'est venu à l'esprit que le javascript natif est généralement plus rapide que jQuery et je l'ai trouvé.
var items = document.getElementsByTagName("*");
for (var i = 0; i < items.length; i++) {
//do stuff
}
Je suppose que l'option native est plus rapide. Vous vous demandez s'il y a d'autres options que je n'avais pas envisagées. Peut-être une option récursive qui itère sur les nœuds enfants en parallèle.
La méthode Javascript Vanilla que vous avez publiée est la plus rapide. Ce sera plus rapide que la solution jQuery que vous avez publiée (Voir mon commentaire sur la question). Si vous ne supprimez ou n'ajoutez rien au DOM dans votre boucle et que l'ordre de traversée n'a pas d'importance, vous pouvez également l'accélérer très légèrement en itérant en sens inverse:
var items = startElem.getElementsByTagName("*");
for (var i = items.length; i--;) {
//do stuff
}
Edit : vérifiez ce benchmark pour voir combien de temps vous pouvez gagner en utilisant le code natif: http://jsben.ch/#/Ro9H6
MISE À JOUR:
N'utilisez pas $('body *')
pour parcourir les éléments. Il sera beaucoup plus rapide d'utiliser $('*')
si vous optez pour la méthode JQuery (voir les commentaires pour plus de détails).
Plain ol 'JavaScript est beaucoup plus rapide, relativement parlant.
En utilisant un test fiddle , j'obtiens environ 30 ms pour traiter 13 000 éléments avec JQuery, et 8 ms pour traiter 23 000 éléments en utilisant JavaScript (tous deux testés sur Chrome):
JQuery: 433 elements/ms
JavaScript: 2875 elements/ms
Difference: 664% in favor of plain ol' JavaScript
Remarque: À moins que vous ayez une quantité incroyablement élevée d'éléments sur votre page, cela ne fera pas beaucoup de différence. De plus, vous devriez probablement chronométrer la logique dans votre boucle, car cela pourrait être le facteur limitant dans tout cela.
Mise à jour:
Ici est les résultats mis à jour lorsque l'on considère beaucoup plus d'éléments (environ 6500 par boucle), j'obtiens environ 648000 éléments en 1500ms avec JQuery et 658000 éléments en 170ms avec JavaScript. (tous deux testés sur Chrome):
JQuery: 432 elements/ms
JavaScript: 3870 elements/ms
Difference: 895% in favor of plain ol' JavaScript
On dirait que JavaScript s'est accéléré alors que JQuery est resté à peu près le même.
Ce n'est pas une bonne idée en général mais cela devrait fonctionner:
function walkDOM(main) {
var arr = [];
var loop = function(main) {
do {
arr.Push(main);
if(main.hasChildNodes())
loop(main.firstChild);
}
while (main = main.nextSibling);
}
loop(main);
return arr;
}
walkDOM(document.body);
Non compris les nœuds de texte:
function walkDOM(main) {
var arr = [];
var loop = function(main) {
do {
if(main.nodeType == 1)
arr.Push(main);
if(main.hasChildNodes())
loop(main.firstChild);
}
while (main = main.nextSibling);
}
loop(main);
return arr;
}
Édité!
Le moyen le plus rapide semble être document.all
(Notez que c'est une propriété, pas une méthode).
J'ai modifié le violon de la réponse de Briguy pour les enregistrer au lieu de jQuery, et c'est toujours plus rapide (que document.getElementsByTagName('*')
).
Il s'agit d'une solution au problème décrit dans les commentaires (mais pas la vraie question). Je pense qu'il serait beaucoup plus rapide d'utiliser elementFromPoint
pour tester la zone où vous voulez placer votre élément à position fixe, et ne vous soucier que des éléments de cette zone. Un exemple est ici:
Fondamentalement, il suffit de définir la taille minimale possible d'un élément que vous recherchez et de numériser toute la zone que votre nouvel élément à position fixe souhaite occuper. Construisez une liste d'éléments uniques qui s'y trouvent et ne vous inquiétez que de vérifier le style de ces éléments.
Notez que cette technique suppose que l'élément que vous recherchez a le z-index le plus élevé (ce qui semble une hypothèse raisonnable pour une position fixe). Si cela ne suffit pas, cela peut être ajusté pour masquer (ou attribuer un z-index minimum) à chaque élément après sa découverte et tester à nouveau le point, jusqu'à ce que plus rien ne soit trouvé (pour être sûr), puis restaurer les après. Cela devrait arriver si vite qu'il est imperceptible.
HTML:
<div style="position:fixed; left: 10px; top: 10px; background-color: #000000;
color: #FF0000;">I Am Fixed</div>
<div id="floater">OccupyJSFiddle!<br>for two lines</div>
JS:
var w = $(window).width(), h=$(window).height(),
minWidth=10,
minHeight=10, x,y;
var newFloat = $('#floater'),
maxHeight = newFloat.height(),
el,
uniqueEls=[],
i;
for (x=0;x<w;x+=minWidth) {
for (y=0;y<h&& y<maxHeight;y+=minHeight) {
el = document.elementFromPoint(x,y);
if (el && $.inArray(el,uniqueEls)<0) {
uniqueEls.Push(el);
}
}
}
// just for the fiddle so you can see the position of the elements
// before anything's done
// alert("click OK to move the floater into position.");
for (i=0;i<uniqueEls.length;i++) {
el = $(uniqueEls[i]);
if (el.css("position")==="fixed") {
el.css("top",maxHeight+1);
}
}
newFloat.css({'position': 'fixed',
'top': 0,
'left': 0});