Poor performance is a deal-breaker when we talk about user experience. Users have little patience when they face slow load times or choppy interactions. They will abandon your site or app within seconds if it does not deliver the expected responsiveness.
But how much time is exactly needed to make the user leave and never come back? Google has already discovered it with the RIAL method (response, animation, idle, and load – key factors affecting user experience).
In brief, users are ready to wait as long as they see the progress. Nevertheless, complete interactions initiated by the user within 100 ms for the best user experience with the smoothest performance without unpleasant delays.
Table of Contents:
Key Performance Metrics
Nevertheless, complex logic and broad functionality are usually cumbersome and affect performance. Fortunately, you can measure the performance and improve key criteria for a better user experience. Time to Interactive (TTI), First Contentful Paint (FCP), and Largest Contentful Paint (LCP) are the most common parameters.
- First Contentful Paint (FCP) measures when the first text or image is displayed. Critical for initial load feel.
- Time to Interactive (TTI) marks when a page is fully interactive without long tasks blocking input.
- Largest Contentful Paint (LCP) tracks when the largest element is rendered. Loading large content slower than 1.5s risks causing poor user experience.
Minify and Bundle Files
There are several ways of changing the code for particular purposes. We’ve already talked about obfuscation and what it’s used for. Minification is the opposite way of code manipulation.
Machines don’t care how your code looks. You can write the whole code in one string, and it will work. Minification removes excess characters browsers can ignore, like line breaks, additional spaces, and comments. All of this non-essential formatting increases file size and negatively impacts download speed. Also, minification does not affect functionality.
One more way to minimize the size of the data that the browser has to download is file bundling. File bundling is the process of composing code and dependencies into a single file.
Minifying and file bundling are considered to be some of the most impactful optimizations you can make, but there are many no less effective approaches.
Synchronous loading means scripts block the parsing of subsequent code like the DOM tree, CSS, etc. This can negatively impact performance.
The key difference is that defer executes scripts sequentially after page load, while async provides true parallelism.
If you can’t choose between them, note that sync is generally recommended when dependencies allow since it provides the maximum benefit to responsiveness and loading time. Defer can also help when some asynchronicity is desired, but order matters.
Prioritize Critical Path Code
The five steps of the CRP are:
- Constructing the Document Object Model (DOM): The browser receives the HTML file and parses it to construct the DOM, a programming API that represents the document’s structure.
- Constructing the CSS Object Model (CSSOM): The browser receives the CSS file and parses it to build the CSSOM, a programming API that represents the styles and layout of the document.
- Layout and Rendering: The browser uses the DOM and CSSOM to calculate the position and size of each element on the page and then renders them on the screen.
- Painting: The browser uses the rendered elements to paint every pixel of the final image on the screen.
- Compositing: The browser combines the painted elements to create the final composite image the user sees.
Lazy Load Non-Critical Code
As a result, core functionality loads faster while non-critical code loads in the background, and users can see and interact with the page much quicker.
Manage Event Handlers
A common pain while building interactive real-time applications is managing event handlers. Rather often, attaching event listeners causes overhead that negatively impacts responsiveness and overall performance. There is a solution – always remove handlers no longer needed to avoid memory leaks.
One more method is event delegation. Attach a single event listener to the common parent element instead of every child element individually to reduce the number of handlers that need to be processed on user actions.
Optimize scroll events with passive event listeners. On scroll events, the listener, by default, blocks any updates to the page until it finishes. This can cause jank or lagginess during scrolling.
When browsers allow specifying the ‘passive’ option with event listeners. This way browsers can asynchronously handle the event and scrolling updates, free from blocking. In some cases, passive listeners boost scroll performance quite significantly.
Throttling, as a method of optimization event handlers, is primarily used when events fire rapidly, like on scroll or resize. Without throttling, your handler would be called on every single pixel change, which is inefficient.
Throttling works by wrapping the handler’s body in a timeout. It delays execution until scrolling stops briefly and then executes several fast events together with a single call.
Any additional events within that delay are discarded. Your code then runs once with the latest information without being overwhelmed. For example, Lodash and many other libraries provide a throttling utility that handles the timeouts automatically.
A similar method is debouncing, which helps to prevent the application from responding to each event. Instead, it waits a short period to see if the user’s interactions will continue before responding.
- You can’t improve what you can’t measure. Use tools like Lighthouse, WebPageTest, or SpeedCurve to monitor the performance.
- Avoid unnecessary re-renders and DOM mutations.
- Cut out any non-essential animations.
- Compress images.
- Implement caching.
Adjust the usage of the libraries. Usually, we use a particular library because of a few necessary features but don’t really need the library’s full functionality. Exclude unused components for faster loading. Also, use libraries that can help reduce the amount of code required to implement certain features. Choose wisely and update them regularly.
These techniques ensure your application’s responsiveness remains smooth even during lengthy user sessions with frequent interactions. Production deployments of real-time apps are where milliseconds matter.