A closer look to page performance
Tags: webdev, performance, tutorial, html
Published: 2023-10-29 15:39:15

Page performance can greatly affect the impact of your web page. The highest [ecommerce conversion rates](https://blog.hubspot.com/marketing/page-load-time-conversion-rates) occur on pages with load times between 0-2 seconds, but referring to [Google Research](https://www.thinkwithgoogle.com/consumer-insights/consumer-trends/mobile-shopping-ecosystem-page-load-speed/) in 2018 the average mobile web page took 15.3 seconds to load. So, It seems to be a relevant issue. 

All modern web frameworks claim to give you the best performance, but even with the most sophisticated solutions you may encounter varying results. Let´s have a closer look to the backgrounds of page performance. 

First, we need some [metrics](https://luciolaria.com/blog/page-speed-insights-understanding-the-performance-report) to see, how pages perform. This are the most relevant measure you can [check](https://developers.google.com/speed/docs/insights/v5/about?hl=de) 
- First contentful paint (FCP)
- Time to interactive (TTI)
- Cumulative Layout Shift (CLS)

With a late **FCP**, nothing happens after a user clicked a link. At a late **TTI** he or she gets a page, but is not responding. And a late **CLS** lets a browser start rendering a page and then redraw the page with a changed layout. This are bad habits we all want to avoid. So, what cases this behavoir? Let´s dive into the details of page rendering.

### RTT and the page load time

Usually, we start loading a new page by inputting a new URL and hitting return, or by clicking on a link. In both cases, the browser needs to fetch a new page. But each http-request takes some time to be a answered and so there are two important metric here

- the Round Trip Time to answer an http-request (**RTT**)
- the time to fully load a file (**load time**)

Each request has to pass several network nodes to reach the server, so time depends much on the average network performance of all connections. And each request has to pass the internet twice, as the response needs to find the way back to the client. 

The server will need some additional time to get the requested data, and the response time may be much longer if files are large or if there are many requests to be handeled in parallel. You can check the response time with [ping](https://www.meter.net/ping-test/), typically, RTT is in the range of 20 - 40 ms, but you will find that there are frequent delays that may increase the resonse time to 500 ms (= 0,5s) and more. 

Ping does not transfer much data, it is just the response delay. To actually use a file, this has to be loaded and parsed by the browser, regardless if it is an HTML-file, a CSS or JS-file or an image. So, for each ressource you need to load, you will get a constant delay plus a delay, that depends on the file size. For small files, the RTT will usually be most important, while for large files, the network speed may be more important. 
 
### How a page is rendered
 
By hitting return on the URL or clicking a link, the initial page is requested. Typically this is some kind of HTML file, that contains the initial page definition. Now, the browser has to wait the first **RTT** until the page is delivered. 

Before the page is actually rendered, the [preloader](https://andydavies.me/blog/2013/10/22/how-the-browser-pre-loader-makes-pages-load-faster/) will read the file and will identify all extenal references on the page, so he can start to fetch this files. As all http-requests can be handeled in parallel, the load time will only depend on the network speed, not on the order in which the page is executed. So, while the browser renders a page, all ressources are already ordered. See the following image to understand the details:

![Rendering](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lvqod5gs8063fb9frlgj.PNG)

The browser can start parsing the HTML or executing scripts on the page, in fact, browsers execue elements on the page in the exact order they appear, as long as they are not marked as async or delayed. If you place a script ontop of any HTML tags, it will not be able to access any DOM elements that are defined below on the page. 

But how can a browser render a page, if the CSS-files are not yet loaded? That is a tricky question, as rendering includes multiple steps:

- First, the browser builds the DOM
- Then is starts rendering the page from the DOM

Usually the browser can start to build the DOM tree, but he has to wait until all CSS-ressources are loaded before he can start to  render the page. 

It may happen that CSS files are delivered very slowly or they are fetched by some fancy Javacscript tool. In the first case, loading the CSS files may inhibit the page rendering (giving you a slow FCP), in the second case the browser will start rendering the page without any CSS and then repaint the page after the final CSS is delivered (giving you a slow CLS).

Broswers are increadibly fast on parsing HTML, but in most cases it will not matter, if the DOM is built from HTML or from some Javascript framework. The RTT is often much longer than anything, that happens in memory. I did some tests with fully dynamic pages, but the DOM building often was finished in less than 2 milliseconds. So any http-request can be considered to be much slower than any DOM operations.

### How to make your pages fast?

I hope you learned, that the logic order of http-requests may play the biggest role on your page performance. If you want a very fast TTI, it is best to place the scripts right at the end of your initial HTML page. This may allow for interactions even before the page is fully rendered (try this with some kind of clock element, that will start to tick before the page is fully rendered). It may even be necessary to inhibit execution with `document.readyState == complete` to ensure, that interaction is not too quick.

#### So, what about frameworks?

Taking the execution order into account, using a dynamic framework can be a double edged sowrd.

- Load the initial page 
- load the framework referenced in you page  
- load the page sources
- Load the templates referenced in your source
- execute the page sources to render your page
- load ressources referenced in your page
 
The way, things are handeled in frameworks may be different, some steps may be execuded in parallel, but some steps can only be performed after the other. Each stept that defines some new ressources to be fetched will cause a RTT as a delay. This is true for external files, but may also be true for database access. If files can be stored in the cache, page load may be much faster the second time you call a page.


### Summary

It is important to watch the order in which a page requests data over the network. Anything placed in the initial HTML-file will be available fast, things that require a series of downloads may slow down your page. So, it can be a good idea to add some dependencies right in your initial page, even if they are used somewhere deep down in the hierarchy of tools you use.  

Bundlers like Vite may cause significant speedup, not only because they reduce file size, but because they reduce the number of dependencies as they put all code into a single file.  

On the other hand, frameworks like Astro or HTMX, that rely on partial hydration, may cause unexpected delays, if your network performance is low and RTT tends to be unreliable high.