2009-12-04 4 views
6

Quelqu'un pourrait me prouver que le conseil donné here (copié ci-dessous) concernant le retrait des éléments dom avant de les modifier et de les réinsérer est toujours plus rapide.Javascript Performance - Dom Reflow - Google Article

En preuve, j'aimerais voir quelques chiffres. C'est génial qu'ils recherchent cela mais je pense que l'article est très faible sans inclure de détails sur ce qu'est le 'problème' et comment la solution se résout en termes de vitesse (comme le titre de l'article Accélérer JavaScript)

article ....

Out-of-the-flux DOM Manipulation

Ce modèle nous permet de créer de multiples éléments et de les insérer dans le DOM le déclenchement d'une seule refusion. Il utilise quelque chose appelé DocumentFragment. Nous créons un DocumentFragment en dehors du DOM (donc il est hors du courant). Nous créons ensuite et ajoutons plusieurs éléments à cela. Enfin, nous déplaçons tous les éléments de DocumentFragment vers le DOM mais déclenchons une seule rediffusion. Le problème

Créons une fonction qui modifie l'attribut className pour toutes les ancres d'un élément. Nous pourrions le faire en itérant simplement à travers chaque ancre et en mettant à jour leurs attributs href. Les problèmes sont, cela peut provoquer une refusion pour chaque ancre.

function updateAllAnchors(element, anchorClass) { 
    var anchors = element.getElementsByTagName('a'); 
    for (var i = 0, length = anchors.length; i < length; i ++) { 
    anchors[i].className = anchorClass; 
    } 
} 

La solution

Pour résoudre ce problème, nous pouvons supprimer l'élément du DOM, mettez à jour tous les points d'ancrage, puis insérez l'élément arrière où il était. Pour y parvenir, nous pouvons écrire une fonction réutilisable qui non seulement supprime un élément du DOM, mais renvoie également une fonction qui réinsèrera l'élément dans sa position d'origine.

/** 
* Remove an element and provide a function that inserts it into its original position 
* @param element {Element} The element to be temporarily removed 
* @return {Function} A function that inserts the element into its original position 
**/ 
function removeToInsertLater(element) { 
    var parentNode = element.parentNode; 
    var nextSibling = element.nextSibling; 
    parentNode.removeChild(element); 
    return function() { 
    if (nextSibling) { 
     parentNode.insertBefore(element, nextSibling); 
    } else { 
     parentNode.appendChild(element); 
    } 
    }; 
} 

Maintenant, nous pouvons utiliser cette fonction pour mettre à jour les points d'ancrage dans un élément qui est hors de la circulation, et seulement déclencher une refusion lorsque l'on enlève l'élément et lorsque l'on insère l'élément.

function updateAllAnchors(element, anchorClass) { 
    var insertFunction = removeToInsertLater(element); 
    var anchors = element.getElementsByTagName('a'); 
    for (var i = 0, length = anchors.length; i < length; i ++) { 
    anchors[i].className = anchorClass; 
    } 
    insertFunction(); 
} 

Répondre

5

Vous aurez du mal à obtenir des chiffres significatifs à partir du profilage javascript car vous économisez vraiment des repeints et des re-flux qui n'apparaîtront pas dans la plupart des outils de profilage. Vous pouvez utiliser le Firebug paint events extension pour afficher visuellement le nombre de repeints que vous enregistrez.

+0

Belle extension mais les deux exemples semblent faire la même quantité de redessins pour moi. Toute chance que vous pouvez donner une démo à pastebin.me :) – redsquare

+0

Je vais admettre que l'extension ralentit beaucoup les choses, donc il peut parfois être difficile de voir la différence sur les opérations lourdes de calcul, par exemple. Google Maps zooming. – Alex

1

La réponse courte est que l'évolution du DOM du déclencheur réel de la page Javascript événements, les évaluations CSS, la propagation des changements affecte l'interprétation du reste du DOM autour, etc. noeuds débranchés en flux n'ont rien de semblable à cela, et les manipulations sont beaucoup moins chères. Une analogie: Si vous étiez un animateur travaillant sur Toy Story 4, et dans un rendu presque final, vous avez vu un changement que vous deviez faire dans la physique du tissu d'une scène, voulez-vous faire vos changements tout en faisant les détails sont-ils restitués pour inspecter la scène, ou désactiver les textures et les couleurs et réduire la résolution pendant que vous faites ces changements?

+0

Je veux des chiffres. Où sont les avantages. La théorie est géniale. Tout comme l'Irak avait WOMD, regardez ce qui s'est passé. Je ne vois toujours pas comment cela rend le js plus rapide. Je l'ai profilé et ne peux voir aucun avantage. Je me demandais juste ce qui me manquait. – redsquare

+0

@redsquare: Le titre de cet article est trompeur et, à certains égards, inexact. Cela ne rend pas nécessairement le JS plus rapide ... il rend le rendu du DOM plus rapide. En d'autres termes, le JS pourrait fonctionner aussi vite (ou même plus lentement), mais la page semblerait plus rapide, parce que le navigateur doit passer moins de temps à repaver et repeindre. Refléter et repeindre est la façon dont le navigateur rend HTML et CSS. Les performances JS ne sont pas les mêmes que celles du navigateur. À titre d'exemple, les tableaux sont coûteux à afficher, même si votre site n'a pas de JS. – Pauan

+0

@redsquare: Je pense que la raison pour laquelle ils l'ont appelée "accélérer JavaScript" est parce que JS est * habituellement * la chose qui déclenche les remboursements et les repeints. En d'autres termes, en changeant votre code JS, vous pouvez faire apparaître la page plus rapidement. Mais il n'apparaît pas plus vite car le JS est plus rapide, il apparaît plus vite car le navigateur est en train de refaire et repeindre moins. Par exemple, une applet Java qui manipule le DOM serait probablement aussi mauvaise, il est donc inexact de l'appeler "vitesse JavaScript". C'est vraiment la vitesse de rendu. – Pauan

2

J'ai mis quelques liens sur une page et testé la méthode dans l'article par rapport à la définition du nom de classe avec les éléments encore dans la page. J'ai essayé ceci dans Firefox 3, IE 8 et Chrome 3.

J'ai fait des classes pour les liens qui avaient la couleur différente et la taille différente de police.Comme le texte du lien avait une taille différente pour les différentes classes, j'étais sûr que la page devait vraiment être rediffusée.

Pour un nombre raisonnable de liens (jusqu'à quelques milliers), enlever et ajouter des éléments est un peu plus lent.

Pour un très grand nombre de liens (10 000), la suppression et l'ajout d'éléments est légèrement plus rapide.

Cependant, la différence est assez faible. Vous devez avoir plusieurs milliers de liens pour être capable de remarquer n'importe quelle différence, et à 10 000 liens il n'y a toujours que quelque chose comme une différence de 20%.

Alors, ce que j'ai trouvé est que vous ne pouvez pas attendre à un changement dramatique de cette méthode. Si vous avez des problèmes de performance, il y a probablement d'autres méthodes qui donnent un bien meilleur résultat. Je voudrais par exemple essayer de changer le nom de classe de l'élément parent au lieu de tous les éléments enfants, et laisser CSS faire le travail. Les tests que j'ai faits auparavant ont montré que cela peut être environ dix fois plus rapide.

0

Il n'y a aucun moyen fiable de savoir quand une refusion est terminée, autre que de regarder la page.

Le temps passé à calculer est pratiquement le même pour ajouter ou modifier des éléments à la fois ou un par un. Le script n'attend pas le navigateur entre les éléments, le navigateur le rattrape.

Parfois, vous voulez voir quelque chose tout de suite, même si cela prend plus de temps pour rendre l'ensemble d'autres fois chose- vous voulez attendre un peu plus longtemps et montrer tout quand il est prêt.

Si vous ne pouvez pas dire ce qui est mieux, obtenir un concepteur de regarder l'un par un et tout à la fois-versions-, mais ne demandez pas deux designers!

2

Ceci est plus ou moins le même que l'utilisation de documentFragments pour initialiser les éléments plutôt que le DOM. Les fragments de document finissent par être plus rapides car ils ont moins de structure et de rendu réel à s'inquiéter.

Voici quelques-unes des notes de John Resig sur les avantages de performance des fragments de document (qui sont utilisés dans jquery actuellement):

http://ejohn.org/blog/dom-documentfragments/