How does browser work step by step [latest] — optimization in the interaction stage (part 5)
Optimization in the interaction stage is about optimizing the frames.
When interacting with the page, a user triggers events. Some events modify the page layout and styles. Depending on the scripts, the browser may need to go through the rendering stage multiple times to continuously deliver new bitmaps or compositor frames to our screen.
FPS and lag
Human eyes can see up to 1,000 frames per second (FPS). In slow or static scenes, we rarely tell the difference beyond 30 FPS. However, it becomes noticeable in dynamic scenes, such as playing first-person shooter video games. Today, most monitors refresh rate is 60 FPS or 60 Hertz.
Ideally, the browser needs to complete the rendering stage and deliver a frame within 1/60 seconds. That is 16.67 milliseconds. If so, a user sees a smooth animation and doesn’t feel lagging.
Reflow and repaint
The height modification doesn’t affect the DOM tree. Instead, it requires style computation.
At the end of style computation, the renderer process reflects the height change to the layout phase, leading to the transformation of the element’s geometry information. Therefore, the layout tree needs to be generated.
The layout tree is the dependency of the remaining phases, so the renderer process needs to go through all steps.
This process is called reflow.
The worst case of the reflow is modifying DOM. An example is “document.body.appendChild(node).” The reflow process starts from the first phase, building the DOM tree.
How about changing the background color of an element?
Again, let’s start with the style computation. The new background color doesn’t modify the element’s geometry information, so the renderer process skips it. It doesn’t create a new layer either, so let’s skip the layer phase. At the paint phase, the renderer process needs to generate a new paint record to reflect the background color update. Then, it goes through the rest of the phases.
This process is called repaint.
Both reflow and repaint lower the rendering performance for two reasons:
- The reflow and repaint process is happening in the main thread, so it cannot take care of any events triggered by users’ interaction. When it happens, the users feel lagging.
- The computation process in the layout, layer, and paint phases are expensive.
Since the repaint skips the layout and layer phases, it is a relatively better option than reflow.
Are there any changes that don’t trigger reflow and repaint at all?
Yes. CSS animation is an excellent example.
A typical CSS animation uses a “transform” property. Modifying “transform” value skips the layout, layer, and paint phases, and starts with the tilling in the compositor thread.
Without occupying the main thread, CSS animation doesn’t block users’ interaction. It is the reason that you still see smooth CSS animation even if the page freezes.
Optimization in the interaction stage is about increasing the speed of frame generation
For example, a significant function could take hundreds of milliseconds to complete. It blocks the main thread and lowers the performance.
We can separate the function to smaller ones, so each of them doesn’t take long. The browser helps optimize the tasks when running the functions.
When the DOM tree is modified, the renderer process will recalculate the style and layout. Usually, the computation runs asynchronously in another task.
Let’s take a look at an example.
What if we check the element height at the end of the script?
When evaluating the element “offsetHeight,” the value is still the old one because the renderer process has not yet computed the style and layout. The renderer process starts the calculation synchronously so it can receive the updated value.
What is worse? We evaluate the attributes in a for-loop. The previous process happens continuously until the end of the execution. Most of the time, a noticeable delay occurs on the page.
In a real-life project, it is hard to avoid evaluating the attributes entirely. However, we can try to minimize usage.
Using CSS animation and “will-change”
CSS animation doesn’t use the main thread at all, so we can use it as much as possible.
Meanwhile, we can attach the “will-change” attribute to the animated elements. An element with a “will-change” is rendered on a stand-along layer in the layer tree, further optimizing the frame generation in the compositor thread.
What improvements coming to our browser in 2020?
There are three levels of views in improving browser performance,