Web Applications: Analyzing Client-Side Performance
A beginner’s guide to the unarguably complex process of analyzing web application performance
The strategies suggested in this post are the result of observing Expedia Group™ Staff Software Engineer Joonas Tanner analyze one of our customer facing applications.
Performance analysis ideally should be agnostic with respect to the underlying UI or server framework. End users (including browsers) do not care if the site was made with React, Vue, or if it is a collection of static files.
What is more important is that the site is fast to use and easy to parse. As such, it’s a good idea to analyze the end product: observe the HTML source and the bundled JS/CSS that gets served to the customers by the application while it’s running in production, or in a production-like environment. Ultimately, just treat the site as a document — which it is.
Analyzing the document — Sources of Truth for Reliable App Performance Analysis Results
The first thing to discuss is which environment should be used as the source of truth when analyzing your application’s performance metrics. The following quote is paraphrased from internal Vrbo documentation regarding measuring application performance:
Performance tests on your local machine are not indicative of performance once deployed.
Therefore, the first source of truth that will provide the most accurate performance metrics will be assessing your application in a production environment.
If for some reason you cannot analyze your app in production, the next closest thing would be a stage environment.
If you really need to tweak and test code changes etc. you can also analyze your app while it is running in production mode locally but this is NOT really a reliable source of information, so always make sure you verify all results in production.
Step 1: Analyze The Network Tab
While viewing your page open up the Network tab in the Chrome dev tools. Ensure you perform a hard refresh (or disable the cache in network tab) to accurately analyze the assets served by your application.
Things to look for:
- Large assets that can be optimized
- Say you have an image on your page that is originally 500px wide but shrunk down to 50px with CSS. This is a performance hit both in terms of slower rendering speed and download speed due to the larger file size.
- If this image does not need to responsively enlarge to 500px then resize and replace it with a 50px version.
- If you do need the image to responsively resize depending on the viewport, one solution would be to implement a strategy that serves the exact image size necessary for the current screen size rather one large image that scales from mobile up to desktop. Also ensure you are leveraging the maximum amount of image compression and optimum image formats.
2. Long-running requests
3. Assets not downloading in parallel. These will slow down the total page load.
4. Identify large blocking resources and, if possible, defer or load asynchronously, or better yet load lazily or use the idle until urgent strategy.
5. Ensure assets are being Gzip’ed server-side.
6. Ensure there are no duplicate asset downloads i.e. the same asset is being downloaded more than once.
Step 2: View the Page Source from Top to Bottom
Inspecting the page output using the Chrome DevTools Elements tab can be unreliable since the DOM tree can potentially be dynamically updated by running scripts so instead opt to utilize the “View Page Source” option to analyze resource loading order/strategy.
The key aims here are to identify resource loading order, verify correct usage of
rel attributes (
preload, etc), and analyze any inline scripts.
Identify large blocking resources that are ahead of critical resources such as the main program bundle and assess whether or not they can be re-ordered or eliminated.
<head> of the document, analyze its size in a code editor, and question the importance of included resources as well as their load order.
- Identify non-critical resources that could be async loaded.
- Identify resources that aren’t necessary unless an explicit action on the page is initiated and lazy load or defer loading after critical resources.
Identify inline SVG code and optimize or eliminate it. For example, if you see duplicated inline SVG code in the DOM consider adding an ID to the SVG code and leveraging the <use> element.
There are several scenarios where JS support may not work including user preference, script errors, and network/loading errors to name a few. Therefore, it is recommended to evaluate your application with JS disabled via the Chrome Dev Tools.
Step 4: Analyze DOM Node Count
Analyze your application’s DOM node count and try to attain a size less than or equal to 1500. A large DOM can increase memory usage, cause longer style calculations, and produce costly layout reflows. Learn more from an excellent blog post written by fellow Expedia Group software engineer Joonas Tanner and from the Google developer docs.
Step 5: Analyzing Application Bundles
This step probably deserves a post (or several) of its own, but in general:
Check for code that is only included for an A/B test variant is not downloaded for everyone. Also ensure any dead code related to A/B tests is removed.
webpack-bundle-analyzer to identify dependencies that accomplish the same goal. For example, if your app is pulling in multiple HTTP clients such as
axios, etc, consider replacing them with
fetch. If they are dependencies of dependencies reevaluate the library and search to see if there's an analogous one that uses
Analyze possible sources of transpilation bloat. An example of transpilation bloat can been seen in React class based vs functional components. Class based components transpile to larger sized files than functional components. Although the file size increase per component is relatively small, those extra bytes can easily add up in a complex web application with dozens of React components. See this excellent blogpost by Drew Walters for details.
In conclusion, when conducting performance analysis of your application make sure you keep things simple by focusing strictly on the output that gets served to your customers in a production environment and not the server or UI framework.
Finally, utilize bundle analysis tools to scrutinize the resources that ultimately are downloaded by your users for bloat and superfluous code.