Home > Software design >  When exactly does the browser repaint and reflow?
When exactly does the browser repaint and reflow?

Time:09-17

I was trying to understand better what happens when DOM manipulations happen in a browser. Something that I could not find a lot of resources about, was when exactly repaints and reflows are executed by the browser (there is a lot of literature what a repaint or reflow is, but almost nothing about when it happens).

Very specifically, I was wondering about code like this:

function clickHandler() {
    domElement1.textContent = 'Hello';
    domElement2.textContent = 'World';
}

Assume that there are two DOM elements stored in the variables domElement1 and domElement2. The clickHandler function is attached to a button, and should update the content of both DOM elements when it is clicked.

Now the question: Is it possible that this causes two repaints? I.e. that the browser updates only domElement1, shows that change on the screen causing repaints/reflows/etc., and afterwards updates domElement2 causing another repaint/reflow/etc.? Or is there a guarantee that the event handler of the button will be completely executed before anything is changed in the actual DOM?

My guess would have been that the browser tries to keep 60 frames per seconds, and that theoretically it could happen that these two changes might happen in two different frames. Is that correct?

CodePudding user response:

Browser reflow and browser repaint are two different, but related, ideas.


Reflow is essentially the computation of the offsets and dimensions of given elements to understand what comes where and takes how much of space, and so on.

Repaint is the next stage after reflow. It is when the computation made in the reflow stage is actually used to paint pixels on the screen. This process is sometimes also known as rasterization.


First thing's first: repaint only happens when the main thread is free, i.e. when no event listener, no callback, just simply nothing is currently in line for execution. And, as I can make its intuition, repaint only happens when a reflow was triggered previously.

In contrast to this, a reflow might be triggered with every single DOM mutation, depending on the underlying code.

As you can reason, the most naive approach for any browser is to trigger reflow after every single DOM mutation (e.g. the domElement1.textContent = 'Hello'; statement that you shared above). But as you might agree, this would be extremely inefficient.

What if there is a whole bunch of such statements in a line? Clearly, in this case, it would be much much better for the browser to do reflow just once at the very end of the whole block of statements and thus keep itself from wasting computing resources.

Now here's one thing to keep in mind. As you may know, browser engines, especially for JavaScript, have become extremely complicated, sophisticated and intelligent over the past few years. These days, they can make extremely intelligent guesses on what a code precisely asks for and then ultimately apply numerous kinds of optimizations over it in order to run it at the top-most speed.

These optimizations include holding on to the execution of the reflow algorithm when there is no need for it. That how every single browser exactly does this is out of the scope of this answer and is obviously implementation-dependent. Chrome might rely on one method, Firefox on the other, Safari on the other, and so on.

There isn't really any point in digging into each one's code bases and finding the exact way it works.

However, there is a common thing between all browsers these days and that is that they try to do the least amount of unnecessary work. That's one of the reasons of the success of modern-day JavaScript — the robust engines are right at its back.

So, to end this answer, I would say that no, there is almost no possibility that the following code would trigger reflow twice:

function clickHandler() {
    domElement1.textContent = 'Hello';
    domElement2.textContent = 'World';
    // Reflow should happen at the end of this function.
}

However, the following might trigger it twice because the second statement wants to know about something (i.e. the distance of domElement1 from the top edge of the viewport) that can only be obtained once the reflow algorithm has been run by the browser:

function clickHandler() {
    domElement1.textContent = 'Hello';
    console.log(dom1Element.getBoundingClientRect().top); // Should trigger reflow.
    domElement2.textContent = 'World';
    // Reflow should happen at the end of this function.
}

Note the usage of the words 'almost' and 'might' in the sentences above. I've used them to emphasize on the fact that I am not 100% sure. There is over 50% probability that what I say does actually happen on every single browser, but the probability is still not 100%. As I said before, engines work differently, and I can't tell you something blindly which I've never inspected myself.

  • Related