I am working on a small JavaScript template engine, and I have two possible approaches for dealing with updates to the DOM when the model changes:
Check if the DOM update is really needed before doing it. This has the benefit of not risking unnecessary updates, but I am wasting space on keeping track of old values.
if (oldValue !== newValue) {
element.textContent = newValue;
}
Just do it. This is obviously simpler, but I am afraid that I will be triggering repaints and reflows for no reason.
element.textContent = newValue;
Note that I am also manipulating the DOM by calling setAttribute
, addClass
and removeClass
, plus setting style[prop] = value
.
So, my question is: Are modern browsers smart enough to notice that nothing actually changed, and therefore not run reflow or repaint, if you touch the DOM without actually changing anything?
Using the MutationObserver
api you can detect DOM
changes.
Here is an example you can use to see if a browser triggers the Dom Changed
event, based on what you want.
You have here both a text('...')
by jquery and an el.textContent
(that doesn't use 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>
- In Chrome 55, only
setAttribute()
and jQuery text()
triggered the Dom Change
event.
- In Firefox 50, everything triggered the
Dom Change
event.
- In Edge 38, everything triggered the
Dom Change
event.