2017-01-03 1 views
4

Je travaille sur un petit moteur de template JavaScript, et j'ai deux approches possibles pour traiter les mises à jour du DOM lorsque le modèle change:Est-ce que toucher le DOM déclenche une refusion et repeindre même si rien ne change?

  1. Vérifiez si la mise à jour DOM est vraiment nécessaire avant de le faire. Cela a l'avantage de ne pas risquer des mises à jour inutiles, mais je gaspille de l'espace sur le suivi des anciennes valeurs.

    if (oldValue !== newValue) { 
        element.textContent = newValue; 
    } 
    
  2. Faites-le. C'est évidemment plus simple, mais j'ai peur de déclencher des repaints et des remboursements sans raison.

    element.textContent = newValue; 
    

Notez que je manipulais aussi les DOM en appelant setAttribute, addClass et removeClass, ainsi que la mise en style[prop] = value.

Alors, ma question est: Est-ce que les navigateurs modernes assez intelligents pour remarquer que rien réellement changé, et donc pas courir refusion ou de repeindre, si vous touchez le DOM sans changer quoi que ce soit?

+2

Les navigateurs sont très intelligents de nos jours. Aucun flux ne se produira s'il n'y a pas de changement, affichez sage. Et même alors, la repeinte ne sera appliquée qu'à la partie de l'écran affectée. –

+0

* Je gaspille de l'espace * Oui, l'espace est à prime ces jours-ci, mon ordinateur de bureau ne dispose que de 32 Go de RAM. –

+1

@torazaburo Garder une copie de toutes les valeurs liées dans un grand SPA est coûteux sur un appareil mobile, et si elles changent souvent, cela produit beaucoup de déchets qui doivent être collectés, ce qui gâche les cadrans. Ce n'est pas un gros effet, non, mais s'il n'y a pas de but, il y a peut-être encore quelque chose à gagner ici. – Anders

Répondre

3

Utilisation du MutationObserver api vous pouvez détecter DOM changements.

Voici un exemple que vous pouvez utiliser pour voir si un navigateur déclenche l'événement Dom Changed, en fonction de ce que vous voulez.

Vous avez ici à la fois un text('...') par jquery et un el.textContent (qui n'utilise pas jquery).

$(document).ready(function() { 
 
    $('#btn1').click(function() { 
 
    console.log('text changed - jquery'); 
 
    $('#a1').text('text 1'); 
 
    }); 
 
    $('#btn2').click(function() { 
 
    console.log('text changed - textContent'); 
 
    $('#a1')[0].textContent = $('#a1')[0].textContent 
 
    }); 
 
    $('#btn3').click(function() { 
 
    console.log('class changed'); 
 
    $('#a1').attr('class', 'cls' + Math.floor(Math.random() * 10)); 
 
    }); 
 
}); 
 

 

 
var target = $('#a1')[0]; 
 

 
// create an observer instance 
 
var observer = new MutationObserver(function(mutations) { 
 
    var changed = false; 
 
    mutations.forEach(function(mutation) { 
 
    // You can check the actual changes here 
 
    }); 
 
    console.log('Dom Changed'); 
 
}); 
 

 
// configuration of the observer: 
 
var config = { attributes: true, childList: true, characterData: true }; 
 

 
// pass in the target node, as well as the observer options 
 
observer.observe(target, config);
.cls1 { 
 
    border: 1px solid red; 
 
} 
 
.cls2 { 
 
    border: 1px solid pink; 
 
} 
 
.cls3 { 
 
    border: 1px solid cyan; 
 
} 
 
.cls4 { 
 
    border: 1px solid darkgreen; 
 
} 
 
.cls5 { 
 
    border: 1px solid orange; 
 
} 
 
.cls6 { 
 
    border: 1px solid darkred; 
 
} 
 
.cls7 { 
 
    border: 1px solid black; 
 
} 
 
.cls8 { 
 
    border: 1px solid yellow; 
 
} 
 
.cls9 { 
 
    border: 1px solid blue; 
 
} 
 
.cls10 { 
 
    border: 1px solid green; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div id="a1" class="cls1">text 1</div> 
 
<button id="btn1">Change text - jquery (keep original)</button><br /> 
 
<button id="btn2">Change text - textContent (keep original)</button><br /> 
 
<button id="btn3">Change class (real change)</button>

  • Dans Chrome 55, seulement setAttribute() et jQuery text() a déclenché l'événement Dom Change. Dans Firefox 50, tout a déclenché l'événement Dom Change.
  • Dans Edge 38, tout a déclenché l'événement Dom Change.
+1

Cool réponse! J'ai mis à jour avec quelques résultats. Une pensée cependant: aucun événement de changement de dom n'implique aucun repaint/refusion. Mais est-ce qu'un changement de dom implique un repaint/refusion? – Anders

+1

En ce qui concerne 'repaint/refow'' - je n'en suis pas vraiment sûr (toujours en train de chercher), mais voici un test que vous pouvez essayer - prendre un élément avec beaucoup de texte (commencer par 1M chars,), et utilisez '$ (el) .text ($ (el) .text())'. Il va déclencher le DOM, parce que c'est par jQuery - vérifiez si le navigateur prend des changements de temps/cpu/scroll pour le faire. – Dekel

+1

Est-ce que certains tests dans FF - ont découvert que le moniteur de performances vous indique quand il repeint et redistribue.Pour les petits textes (1K charas) il déclenche parfois une repeinte, mais pas de refusion. Pour les textes volumineux (caractères de 1M), il déclenche une refonte coûteuse et repeint à chaque fois. – Anders