Talking about Front-end and Performance

Alan Sosa (Argentina GMT-3)
Globant
Published in
6 min readDec 16, 2022
Photo by Marc-Olivier Jodoin on Unsplash

In this article, we’ll dive into performance topics related to Web UI. As front-end (FE) developers, sometimes we don’t think about performance as we should, so it’s imperative to keep these topics in mind when we write down some code. Even though we will be talking about vanilla JS, the concepts exposed apply to every JS framework, since JS is the core of the most popular frameworks we use nowadays.

The computer graphic rendering process

First, we must understand how content is processed to appear on our screens. For the sake of keeping this article as simple as possible, let’s say that the way that the content gets painted on our screens follows the computer graphics pipeline, which looks like this:

I won’t dive into this process very much, but it is essential to keep the concept in mind; it may not make too much sense right now, but it will as we move along in the article. In a simple world, most of this process is managed by our GPUs. Essentially, the computer first makes points (vertices) in the form of triangles, then the program connects those points with lines, and after that, it rasterizes the inside area; once that is done, it can paint each pixel, and when that process is finished, we finally get the output rendered on our screen.

The web rendering process

We just saw how we get graphics on our screens and how most of the rendering engines work, but now we need to understand how the rendering process works on the web. Our websites always contain HTML, CSS, and JS files. So the process looks like this:

  • When loading a web page, the server sends (in bytes form) the required files to the web client.
  • The browser engine converts these bytes into characters according to the specified encoding of the file. Those individual characters are converted into tokens, nodes, and, finally, the object model.
  • The browser converts the nodes into a tree structure; we know this as a DOM. The DOM is the Document Object Model, a logical tree that makes our life easier when we want to manipulate our web from JS.
  • The browser also parses the CSS code into CSSOM (CSS Object Model).

Probably you’ve already seen the DOM structure, but this is what CSSOM looks like:

Image by Ilya Grigorik from web.dev

The previous image shows how our CSS code gets associated with a node; this structure is very similar to the DOM tree. Essentially, CSSOM is a tree where each node has our CSS properties. Specificity is also essential in this point because, at this point, all overrides in our CSS are also considered inside our nodes.

Now that we have a better idea, we can jump into the next topic.

The natural render pixel pipeline

My main goal with this article is that you, the reader, understand that this is the most important concept for FE developers in terms of performance. If you adopt these concepts as a developer, you’ll always know when you are breaking the natural render pixel pipeline.

The natural render pixel pipeline in action

In the image, we can see five different phases. In each phase, we can unintentionally introduce bottlenecks in the rendering process. And I would like to mention rasterization again. First, let’s go and open your DevTools on a test page and go to the Performance tab and activate the screenshots option like this:

Obtaining a technical performance report for a website

In the image above, you can see that you can start profiling by clicking the “reload” arrow. That will start a performance recording of your website. A performance recording is basically the performance profile of a website; it will contain all the things going on in the main thread, screenshots, web workers, FPS, and other interesting things.

When you see paint (see the screenshot from the top right corner of the following image) on the page, you should remember that rasterization is happening. This is because to paint content on the screen (as we saw in the computer graphic pipeline), the engine must create a task for a draw and then fill the pixels.

The image below shows a complete performance report of a website (you can learn more about this here), including FPS information, network requests, memory leaks, and a big et cetera.

A complete performance report of a website, here you can observe scripting and painting times and other information.

Playing with natural render pixel pipeline

Let me explain. While using JavaScript code to manipulate the DOM or some CSS transitions, you can cause a reflow on the page. Every time you change something related to the geometry of an element, you will trigger the natural render pipeline again.

Let’s suppose that you change the width of an element: then you are changing the geometry. The browser engine will recalculate and check if other elements are affected by it, which will cause a reflow.

All the affected elements will need to be repainted; after that, they will go through the composite phase again.

If you change some property related to the painting process, like the background color of an element, then you’re triggering the painting phase only and skipping the layout phase.

And finally, if you change the composition of your layers, then you’ll only trigger that phase. You can trigger the Composite layer by changing the z-index with JS or by using CSS. Also, you can change the composite of your layers by using translateZ in your transform property.

This is the lightest rendering effort, but it doesn’t mean that it’s impossible to have issues; sometimes, you can cause a “layer explosion” (if you constantly stack layers), and nobody wants that.

It is important to mention that causing a layer explosion is very uncommon because of the “layer squashing” (read the layer explosion reference) process of the browsers tries to avoid this. But let’s keep that for our next article about performance.

Changing classes that override (and constantly update) other styles can cause a reflow of your website and also layout trashing. Also, be careful when you do subtree node modifications.

Another important thing to remark is that triggering the browser to synchronously calculate the style and layout of elements will generally cause layout trashing, so when we calculate or change elements sizes then it’s possible to introduce some performance bottleneck.

Conclusion

We’ll talk more about reflow in the following articles, but for now, I’ll list some of the things that can cause the reflow of your website:

  • Adding or removing classes, elements, or styles
  • Changing the orientation of the viewport
  • Calculating or changing size or positions (be careful with getBoundingClientRect because this native API synchronously calculates the size of the elements)

When you want to add some nodes to your DOM using JS, remember the concepts discussed in this article. You’re probably thinking about how all of this looks on code, and the truth is that things are straightforward when we talk about performance, but that doesn’t mean “easy”. But don’t worry; I plan to review everything related to Front-end Performance in the following articles. In future chapters, we’ll discuss the following:

  • DevTools, performance profiler, and JavaScript profiler
  • Network processes
  • Performance test
  • Layout thrashing (real-world examples)
  • Memory and CPU leaks

If you want to dive into the exposed topics, then you can take a look at these links:

--

--