Back to Blog

Web Performance - Renderland's Saga, Book 1

Emmanuel Daniel

Web Performance - Renderland's Saga, Book 1

Where Everything Began - First Act

"Knowledge is like money: to be of value it must circulate, and in circulating it can increase in quantity and, hopefully, in value." ~ Louis L'Amour

In February, I had a task to improve the performance of an NFT marketplace. I had surface-level knowledge of web performance at the time. I spent an insane amount of time researching and watching tech talks and videos so I decided to write this article to make the journey easier for you.

The Portal 👨🏿‍💻

Aimlessly looking for answers with a gazillion tabs open, my PC freezes with no solution in sight. I decide to shut it down and then go out for a walk to clear my thoughts.

I return 30 minutes later to find a strange blue light emitting from the room. It was coming from the PC which was still on but frozen. I try long pressing the power button but I end up getting sucked into the screen instead.

The Giant Robot

I wake up in this weird-looking room where I immediately get approached by a giant robot with the letters HTML on its chest.

🤖 Hi, I'm HTML5. I'm glad you woke up, welcome to Renderland!

👨🏿‍💻 Where am I?

🤖 You're in Renderland.

👨🏿‍💻 Render what???

What is Renderland?

Renderland is the planet on which Rendering takes place. It's the closest planet to the screen and it's what users see and interact with. It's located in the Browser's Solar System which is also under the The Web Galaxy.

This diagram shows how a typical request travels through the internet before it reaches a server that sends back a response to the client.

The response manifests different entities such as Styles, Markup, Scripts, Fonts, and other files. They represent the different life forms on Renderland. They live together to make up the content that you see and interact with.

The Citizens of Renderland 🪐

HTML, the planet's elder summoned us all for a meeting under the Sacred Tree.

🤖 1 I'm HTML, you've probably met my grandson, HTML5. We're both from the Markup tribe and we make up the content of pages on the web.

🤖 2 I'm CSS from the Styles tribe, and we give web pages looks and style.

🤖 3 I'm JavaScript but you can call me JS, I'm from the Scripts tribe- no relation, and we make web pages interactive.

HTML 🤖 A prophecy spoke of a FullSnack Engineer with a mechanical keyboard and an E mark who'd save Renderland. The Engineer spoke an ancient language called Code.

JS 🤖 We believe you're the chosen one.

Renderland's History 🕰

Long ago, the robots lived in a faraway land known as Serverland where they served a group of entities called clients. The clients lived in Clientland and they all had different shapes and sizes.

A ServerLand native is referred to as a server and a Clientland native is referred to as a client.

The request-response-cycle is a model that describes how clients and servers communicate over a network via a protocol such as HTTP or Web Sockets.

Rendering

Rendering is the process of turning a web page's assets (HTML, CSS, JS, and other static assets) into interactive content on the browser. Rendering steps include style, layout, paint, and, in some cases, compositing.

Critical Rendering Path (CRP) 🛣

The Critical Rendering Path represents the sequence of steps the browser goes through to convert the HTML, CSS, and JS into actually visible pixels on the screen.

The Render Tree 🌲

HTML5 and CSS then summon me into another private meeting under the Sacred Tree. They began explaining the history of the tree and how it came to life.

  • Document Object Model (DOM) describes the structure browsers use to represent HTML elements internally.
  • CSS Object Model (CSSOM) describes the structure browsers use to represent CSS styles internally.

Both are represented internally as a tree-like structure that allows programs to interact with the CSS and HTML content of a web page.


<head>
    <title>Renderland</title>
</head>
<body>
    <header>
         <ul>
             <li>Book 1</li>
             <li>Book 2</li>
         </ul>
    </header>
    <main>
        <h1>The Sacred Tree </h1>
    </main>
</body>

The Render Tree is the product of combining DOM and CSSOM trees. It defines the structure of a web page. The tree contains only the visible elements of a web page.

The browser calculates the layout of each visible element and then paints it on the screen with the help of the Render Tree.

Layout (Reflow) 🗺

Browser computes the geometry of the layout and its elements based on the render tree.

Paint 🎨

Browser paints pixel by pixel to create the visual representation we see on the screen. Using the Render Tree, the browser engine calculates the position of each visible element of a web page.

Rendering in Short

  • Assets Converting the web page's HTML and CSS code into DOM and CSSOM.
  • Render Tree Constructing the Render Tree by combining DOM and CSSOM.
  • Layout Calculate the size and position of each node.
  • Paint painting elements on the browser's screen for users to view.

Rendering Patterns

The robots then began explaining how rendering is practiced in Renderland.

Server Side Rendering (SSR) 🛠

The most ancient form of Rendering. This pattern generates the full HTML for the page content to be rendered in response to a user request.

Client Side Rendering (CSR) 💻

This form of rendering became popular during the Ajax era in 2005. Ajax which stands for Asynchronous JavaScript and XML allowed developers to build client-side applications.

In this pattern, the server renders a skeleton of an HTML container whilst the client handles the logic required to render a web page. The client takes care of fetching, templating, routing, etc.

Guardians of Renderland (The Pillars 👺)

Also known as the Web's Vitals, they are Renderland's guardians of performance. They measure and report any issues that may affect the performance of a web page.

This screenshot is from Lighthouse's report on Hashnode's home page.

First Pillar (First Byte) 1️⃣

This Pillar is responsible for reporting the arrival of the very first byte of incoming data. It helps quantify a server's response time by measuring the latency of a round trip to and from said server. It precedes every other Pillar.

Time to First Byte (TTFB) The time between the initial request and the arrival of the first byte.

Second Pillar (Paint) 🎨

This Pillar measures the time a browser takes to paint pixels on a screen. The shorter the time, the better the performance.

First Paint (FP)

The first instance of content that appears on the browser. Think of it as the first drop of water when you open the tap.

First Contentful Paint (FCP)

Measures how long it takes the browser to render the first piece of DOM content after a user navigates to your page.

💡 The recommended FCP score is 1.8 seconds or less.

Largest Contentful Paint (LCP)

The time when the main page content becomes visible. It consists of the initial HTML document + LCP Resource.

💡 The recommended LCP score is 2.5 seconds or less.

Third Pillar (Time to Interactive) 🎬

Also known as (TTI), represents the state at which a web page is ready to respond to events and user interactions. This is made possible when all the Scripts tribe members have arrived/loaded.

TTI is reached only after FCP. Having a huge gap between these two metrics causes serious problems.

💡 The recommended TTI score is 3.8 seconds or less.

Total Blocking Time (TBT)

The total amount of time between FCP and TTI. It means that the event handlers are registered for the most visible page elements, and the page responds to user interactions within 50 milliseconds.

💡 The recommended TBT score is 200 milliseconds or less.

Measuring Performance

You can't improve what you don't measure. - Peter Drucker.

Learning how to measure performance on the web is crucial. The previous section introduced the Pillars, the section will show you how they perform their duties.

💡 How is performance measured?

  • Field Testing Involves real users loading and interacting with the page.
  • Lab Testing Using tools to simulate a page load in a predictable environment.

Field Testing

Also known as Real user monitoring (RUM) refers to the process of recording user interactions on a production website.

Examples of RUM software: InfluxDB, Google Analytics, CloudFlare, Stackify, etc.

This topic is beyond the scope of this article so we'll jump right into Lab Testing.

Field tests can be conducted using

Lab Testing

Refers to the process of testing an application in an environment such as development or staging before the site is released to the public.

Lab tests can be conducted using


Attack on Renderland 👾 - Second Act

"If you know the enemy and know yourself, you need not fear the result of a hundred battles. If you know yourself but not the enemy, for every victory gained you will also suffer a defeat. If you know neither the enemy nor yourself, you will succumb in every battle." - Sun Tzu, The Art of War.

We receive multiple reports from different locations. Web pages are unresponsive, some fail to load and others are painfully slow.

It was later revealed that Renderland is being invaded by an intelligent species of bugs. They came in different shapes and sizes and wreaked havoc on the planet.

Bugs 👾 vs Pillars 👺

The bugs have directed their first attack on the pillars. Let's see how each metric affects performance.

First Pillar (First Byte) 1️⃣

The bugs decided to lay a siege on Renderland by cutting off its supply routes. They initiated by attacking Serverland aka the source, where the planet's data comes from.

TTFB is affected by many factors, some are within Renderland's territory and others are in faraway planets such as Serverland and Cacheland. Defeating the bugs that have attacked this pillar will take a lot of effort.

The following factors may affect TTFB

  • The Network protocol, HTTP/1 instead of HTTP/2 for example.
  • Longer network request phases. You can learn more about this here.

Second Pillar (Paint) 🎨

The bugs used a set of advanced attacks to target this Pillar. They knew that having a large bundle size or simply blocking the Critical Render Path CRP would have the potential to deal great damage to Renderland.

The bugs did both, they first infected unoptimized assets with a virus which resulted in really large bundle sizes and then blocked the CRP, thus making it difficult to render anything.

Third Pillar (Interactivity) 🎬

The bugs launched their attacks on unoptimized JavaScript. Unoptimized scripts can slow down performance because they need to parsed and compiled before they're finally executed.

💡 What is a Main Thread? JS derives its power from its Main Thread. This article might be a great resource if you aren't familiar with JavaScript's single threaded nature.

The main thread is where a browser processes user events and paints. The browser uses a single thread to run a page's JavaScript, as well as the Critical Rendering Path.

The bugs decide to attack this Pillar by overwhelming/overworking the main thread because they browser may not respond to user interactions if the main thread is blocked/occupied by another process.

Miscellaneous Performance Bottlenecks

These are some of the most common web performance bottlenecks.

Unoptimized Resources

Resources which haven't been optimized are prone to the virus. Scripts, styles, and HTML imports may block or delay the browser from rendering content to the screen.

Bundle Size

This is the amount of JavaScript a user will have to download to load your website. A larger bundle size means users will have to wait longer before they could interact with your site.

Network Requests

Enormous network payloads reduce the application's performance. Also, higher latencies make requests take longer to travel to and from the server.

DOM/CSSOM Bottlenecks

  • Event handlers are costly.
  • Layout thrashing and reflows cause re-renders meaning the browser will have to recalculate and re-paint content with every reflow.

The Render League ⚔️ - Third (Final) Act

"With great power comes great responsibility."

The natives of Renderland formed an alliance known as The Render League to combat the bugs and defend the planet. Each alliance member has a special set of abilities that can be used to help improve a performance metric.

Learning how to measure the performance of a website was the first step. Now we need to learn how to optimize the metrics we measure.

First Pillar (First Byte) 1️⃣

This metric indicates how fast or slow a server is. It measures the latency of a round trip to and from a server.

How to improve TTFB

Let's see how we can fight back these bugs!

On the Client

  • Caching assets and requests with the use of web/service workers (more on these later).

On the Server

  • Better server infrastructure (Using Load Balancers and Caches) for example.
  • Pre-connect to required origins for cross-origin resources.
  • Using HTTP2 if possible.

Second Pillar (Paint) 🎨

To defend this Pillar, the alliance sent a special team known as the Assets or simply as the A-Team. It consisted of HTML, CSS, JS and many others.

NB: Every Renderland native posses the ability to shrink themselves. This ability is known as minification.

The A-Team laid out a brilliant plan to fix FCP and LCP.

Optimizing Assets

Assets who were optimized were immune to the virus.

💡 How?

  • Use minification on CSS, HTML, JS and other assets so browsers can download them faster.
  • Optimize resource load times, for example compressing images, serving them in different sizes, using a CDN, etc.
  • Compressing, removing unused code and deferring non-critical scripts or styles.

Summary

  • Reducing TTFB.
  • Optimization and caching assets.
  • Shortening the Critical Rendering Path.
  • Using 3rd party tools such as Cloudinary.

Third Pillar (Time to Interactive) 🎬

The robot JS and I paired up to help improve this metric while the other assets remained to defend FCP and LCP.

How to improve TTI

In order to improve this metric, JS and I will have to accomplish the following objectives:

Minimizing Main thread's work

Shinobis in Nauroto) are known for their Clone Jutsu technique which enables them to create multiple clones of themselves. JS can also summon other threads such as Service Workers or Web Workers to delegate work.

Book 2 of the Saga will cover this topic.

Debouncing Events

JS also has the ability to slow down time at will! JS can use this power to delay the execution of event handlers to increase performance because it helps the browser avoid fast consecutive events. These events can block frames from completing, and can cause additional and unnecessary layout work.

💡 How to Debounce?

  • Leading Debounce executes a function once and waits until there's a pause in consecutive events.
  • Trailing Debounce postpones a function's execution based on a time interval.

🪛 Benefits/ examples

  • Dynamic search bars.
  • Saving content as a user types, for example Hashnode's editor does this :)

Minification

Being a a Renderland native, JS is able to downsize or minify itself so it can travel quicker when it's needed.

💡 How to minify?

  • Using a CDN provides automatic minification.
  • VSCode supports minification for several programming languages.

🪛 Benefits/ examples

  • Scripts travel through the network faster.

Code Splitting

JS can also split its body parts and have each body part can perform a task/function.

For example, let's consider a web app with three pages, namely home, chat and notifications. Code-splitting allows you to download only the JavaScript relevant to your home page and then download the remaining assets on-demand.

💡 How to Code Split?

  • Using a bundler such as Webpack or Browserify.
  • Using a framework that provides code-splitting by default such as Next.js.

🪛 Benefits/ examples

  • Downloading code in chunks or in parallel can help reduce an app's bundle size.

Event Delegation

If a web page has a lot of elements with events that could be handled the same way, delegating the event handler to a common parent can potentially improve performance,

💡 How to delegate events?

  • Putting a single handler in the container.
  • Handle event based on the event's target.

🪛 Benefits/ examples

  • Less code and more control over event handling.

Throttling

Throttle prevents a function from executing more than once every specified amount of time. It guarantees the function execution once every specified amount of time.

💡 How to Throttle?

  • A bit similar to debouncing, you'd use a time interval.

🪛 Benefits/ examples

  • Preventing repetitive function execution.

Miscellaneous Performance Tips

Re-Renders

  • Detect and eliminate unnecessary re-renders. Why did you render is a great library if you're building an app using React.

Memoization

  • Memoize values with React.memo/callbacks.

Packages

  • Analyze your packages if you're using WebPack. WebPack Bundle Analyzer is a great choice. I've personally used it to improve the performance of an NFT marketplace.

Conclusion

Choosing the right tool for the job is a critical skill for every Software Engineer. Software choices are usually determined by the project's requirements.

Resources 📚

I'm currently working on a few more sagas. Let me know if you're interested in more sagas in the comments below 😁

NB: Part 2 of this article. will explore the practical aspects of web rendering performance. I decided to break it into two parts because I don't want to overwhelm the reader.

Fun Fact: This article's story line was inspired by

  • This Tweet
  • Lupe Fiasco's The Cool.
  • Demon Slayer: Kimetsu no Yaiba.
  • Marvel Movies (Thor, Spiderman and Thor 2).
  • Attack on Titan.

Share on social media: