Question: Does touching the DOM trigger a reflow and repaint even if nothing changes?

Question

Does touching the DOM trigger a reflow and repaint even if nothing changes?

Answers 1
Added at 2017-01-03 23:01
Tags
Question

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:

  1. 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;
    }
    
  2. 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?

Answers to

Does touching the DOM trigger a reflow and repaint even if nothing changes?

nr: #1 dodano: 2017-01-03 23:01

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.
Source Show
◀ Wstecz