March 5, 2018Gregory Rosenbaum

The Hidden Life of the Your Web Browser – Visual Upkeep

Let’s imagine for a second you’re writing a technology that is meant to be integrated with another web application. You might believe you have total control over your technology’s performance.

For example, you can think up a new, more optimized way to deliver your resources to clients such as investing in an excellent CDN, optimizing your DOM operations, or other things.

However, today as modern web browsers and layout engines become more complex, different bits of JavaScript (JS) can easily interfere with the performance of your technology in unexpected ways.

We see this this all the time when we monitor web applications using our platform at Reflectiz. Our data shows that even if a technology appears to cause a severe impact on performance, it’s not always to blame, and the root cause is instead something else.

Another phenomenon is constant change. Even if you, as a developer, haven’t made any changes in your technology or site, it doesn’t mean your technology won’t be affected by changes in another component inhabiting the same web application.

There are several things that can make this interference happen. In this article, we will focus on what we call visual upkeep, which includes layout reflow, style recalculation, layering and other operations.

As you might already know, an average web application now uses hundreds of JS technologies, just to operate properly and maintain its reasonable performances. Currently, there’s not much you can do. Tracking general browser information cannot provide you the effective technology overview you really need. In fact, most traditional monitoring platforms give you slices of micro data instead of the big picture, instead of the technology overview you need.
This is one of the reasons that lead us, here at Reflectiz, to develop a unique toolbox that allows vital control over technologies and since we’re talking about control here, we’ve even decided to call it RefControl.

Now, let’s go deeper.

Visual Upkeep: An Introduction

    Visual upkeep operations

Visual upkeep occurs when the browser tries to keep the image on the user’s browser window in sync with the logical structure of the document. When an upkeep operation executes, the JavaScript environment becomes frozen.
This happens so that the JS environment doesn’t catch the document in an intermediate state. Upkeep operations doesn’t directly notify the JavaScript environment, and the only way to track them is by running a profiler, but even that doesn’t really give you the information you need.
Visual upkeep consists of several different types of operations. Each operation depends on the results of the previous ones. We will explain it in more detail in this article.

1. Recalculating styles
2. Layout reflow
3. Layering
4. Painting

The browser doesn’t run the upkeep process every time something changes; instead, it works by invalidating parts of the page.
Some DOM operations mark parts on the page as invalidated or “dirty”, which basically means that the image painted on the window no longer corresponds to how the document is supposed to look. It essentially tells the browser, “you need to redo these bits of the page later on”.

Operations can invalidate specific parts of the document in specific ways, such as invalidating the layout portion, but not the style portion. Despite this, some upkeep operations rely on others. Layout reflow does need style information, for example, so if the styles are invalidated – the layout might be invalidated too.

Once invalidated, a portion of the document eventually needs to be recalculated. But it is crucial to understand that visual upkeep is very hard work, and repeated changes to the document can throw previous calculations away. Accordingly, the browser tries to delay it as much as it can to avoid doing the same work twice for no purpose.
Operations that invalidate parts of the document include changes to the style of an element (for example, changing element.style), adding or removing DOM elements, and changing the class attribute. This resource contains a table of CSS resources and the upkeep operations they trigger through invalidation.

Some JavaScript operations can force a specific upkeep operation. This will cause the upkeep to be performed during the script’s execution, in the middle of the forcing method call. Upkeep is never done half-way, so when it’s forced, all the invalidated portions of the page will need to be recalculated. Needless to say, it’s a bad idea to force upkeep operations.

Forcing operations typically ask the browser for the results of an upkeep operation in the middle of a script. For example, getComputedStyle essentially asks the browser for the results of style recalculation, so it has no choice but to do it immediately.

  • Example of forcing style recalculation in a script

This resource contains a list of operations that force upkeep.
In modern browsers, upkeep will not be performed in the middle of a script, unless the script forces the operation. It can be performed in between scripts (for example, between the end of one script tag and the beginning of the next) or during idle time. The browser decides when best to do it using various heuristics. It’s important to note that these are inherently non-deterministic, and can have very different results between page loads.

The upkeep operations

Recalculating Styles

This upkeep operation recalculates the styles that apply to each element. It doesn’t draw each element or visually apply every style command; it simply takes all the style rules in the application and determines which of them should be applied on each element.
It also determines which directives override which. For example, if two selectors set font-size, style recalculation determines which directive actually modifies the size of the text in the element and which directive is suppressed. In other words, this process determines the result of the getComputedStyle function. Calling it will force the operation.

Reflowing layout

Reflow primarily involves calculating the dimensions and positions of each element. It determines the true width of elements with width: 50%, how to wrap text, and how to break a series of inline elements. In the JavaScript environment, the reflow affects the values of properties such as clientHeight and functions like getBoundingClientRect. Calling them will force the operation.

Layering

    Layering happening after a forced layout reflow

Layering determines how to paint elements that are located in the same place, such as “which element appears on top” and “what part of the lower element it blocks”.
Layering doesn’t have a forcing operation. This is because there is no JavaScript function that asks, is element A on top of element B? This means that layering is never performed in the middle of a script. However, some DOM operations can invalidate these calculations and end up creating more work of this type.

Painting

Painting is when the browser paints the abstract structure of the document. This means taking all the information from the other upkeep operations and turning it into an image which can be displayed on the screen. For painting to happen, the other operations need to be finished first. Multiple painting operations can happen in parallel, painting different parts of the window.
This operation is typically quite fast, because a lot of the work has already been done in previous upkeep operations and because painting a browser window is a relatively simple task for the graphics hardware. Like layering, this operation cannot be forced.
Layout thrashing

    A thoroughly thrashed layout

Although layout thrashing isn’t the primary subject of this article, we couldn’t really avoid mentioning it.
Layout thrashing is a situation where the page is invalidated and upkeep is forced multiple times in the execution of a single script. This is a serious performance issue, but it’s local to your code, so you can usually fix it.
Here is an example of layout thrashing:

let container = document.getElementById("container");
for (let i = 0; i < 100; i++)
{
let div = document.createElement("div");
invalidate the element by changing its subtree:
container.appendChild(div);
//force layout reflow immediately by asking its height:
let newHeight = container.clientHeight;
console.log(`My container is now ${newHeight}px tall!`);
}

Calling Element.clientHeight forces reflow.
The above code basically eliminates all the immense benefits of lazy upkeep by forcing reflow after every element is inserted. The positions of the elements on the page will need to be calculated multiple times, but to no purpose, as each element added makes the previous calculation useless. Layering and painting aren’t a layout thrashing issue because they can’t be forced and layout reflow doesn’t depend on them.

What all this means for us

Well, to start with, its means that in today’s web environment, you’re not fully in charge of how your technology performs in other web applications, and you need to use external services to verify it’s working properly. Visual upkeep is one example. No matter how much effort you make to optimize your technology, it will still be affected by the other code on the page. As we’ve talked about, this is because the work done to render your technology is grouped with all the other work the page is doing at the same time.

It also means that if you force upkeep, besides hurting the browser’s ability to optimize upkeep operations, you can end up doing a lot of the work scheduled by other scripts, making your technology seem extremely expensive when the page is profiled.
When the page is profiled, it can be difficult to understand which script caused a recalculation to become so expensive, and thus – which script has the greatest impact on the page. Because upkeep is essentially non-deterministic, and because performing upkeep at different times can end up being more or less efficient, pages can perform differently between one profiling session and the next.

Lastly, visual upkeep in modern browsers makes heavy use of your GPU. If your computer has a dedicated graphics card, upkeep can be an order of magnitude faster than if you only had an IGP such as Intel HD Graphics. Similarly, a machine that doesn’t have a GPU of any kind will do these calculations even slower. Bear this in mind when profiling your technology or web application.

That’s it for this article, feel free to comment and subscribe for more by Reflectiz – Digital Technology Intelligence.

Subscribe



Join us



Related Articles

REFLECTIZ’s Performance Module Helps Address Severe Issues on Major Websites

REFLECTIZ’s Performance Module...

While most websites monitor their third-party technologies for load speed…

Did you hear how Ad-Blocker Plus is increasing their revenue? By selling Ads!

Did you hear how Ad-Blocker Plus...

Yes, you heard it right. The monopoly Ad-Blocking company, Ad-Blocker Plus has decided to offer a new surprising service which is ads…