问题
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?
回答1:
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 jQuerytext()
triggered theDom Change
event. - In Firefox 50, everything triggered the
Dom Change
event. - In Edge 38, everything triggered the
Dom Change
event.
来源:https://stackoverflow.com/questions/41453465/does-touching-the-dom-trigger-a-reflow-and-repaint-even-if-nothing-changes