Shining a Light on Performance

Yoav Niran
Cloudinary Engineering Blog
8 min readDec 31, 2019
Yoav Niran speaking at “Because Performance Matters”

By: Yoav Niran

Yesterday I presented a lightning talk about performance at the Javascript Israel Meetup: “Because Performance Matters” at the Google Campus in Tel Aviv.

The talk covered 8 topics (inspired by the just ended 8 days of Hanuka), each with several tools and tips.

For most people, finding performance issues and tackling them feels a lot like this:

Photo by Ian Espinosa on Unsplash

And you could say that there’s an ocean of information out there to learn from. It’s not easy to understand where to start.

In the effort to shine a little light in the darkness I thought I’d share the list from my presentation here. It should make for a good roundup post, covering a wide range of tips and tools that form a solid basis for you to read up on if you wish to become better at monitoring, debugging and improving your application performance.

Here we go:

1. Lighthouse & PageSpeed Insights

You can run lighthouse audit from your chrome devtools:

When you run the audit (as someone from Walmart probably should) you get a score for the currently opened page and a detailed report:

lighthouse score for walmart.com homepage

The following sections in the lighthouse report give a very detailed explanation of the areas that should be improved with links to excellent and relevant information:

Concepts such as First Meaningful Paint, Time to interactive, and First CPU Idle are important ones to get acquainted with.

A similar report can be obtained by running a test on PageSpeed Insights:

PSI gives you results for mobile and desktop

Useful Links

● PageSpeed Insights:
https://developers.google.com/speed/pagespeed/insights/

● Lighthouse homepage:
https://developers.google.com/web/tools/lighthouse

● Video: Use Lighthouse and Chrome UX Report to optimize web app performance:
https://www.youtube.com/watch?v=UvK9zAsSM8Q

● Web Fundamentals — Performance
https://developers.google.com/web/fundamentals/performance/why-performance-matters

2. More Tools

Lighthouse CI can be integrated into your build flow so you can be more quickly alerted to regressions with your app’s performance. See more about this in the useful links section below.

Rendering Tab (Chrome DevTools)

Under the console section of your chrome dev tools (CDT) you can find the rendering tab (you might need to add it first, ctrl+shift+P or cmd+shift+P , type “rendering”).

Here you’ll find a plethora of tools that can help you find issues within your app. One such tool is Paint Flashing. It will flash green areas that repaint:

paint flashing in google slides

Notice how different parts of the UI flash green as a click happens. This can be an indication your app is doing more than you’d expect as part of the interaction and can lead to useful debugging investigations.

Useful Links

● Lighthouse CI:
https://github.com/GoogleChrome/lighthouse-ci/blob/master/docs/getting-started.md

● Performance Testing using Lighthouse CI Action:
https://qainsights.com/performance-testing-using-lighthouse-ci-action/

● Analyze rendering performance with the Rendering tab:
https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/reference#rendering

3. Memoization

“…memoization is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again…”

Here’s an example of a simple (cache of one) memoization function:

default memoize function from re-select

Using memoization helps us save calls that would generate the same result. Instead of running the same javascript code which can be intensive we cache the result and re-use it in case the arguments remain unchanged.

Useful Links

● React:
- React.memo: https://reactjs.org/docs/react-api.html#reactmemo
- useMemo hook: https://reactjs.org/docs/hooks-reference.html#usememo

● Reselect: https://github.com/reduxjs/reselect

● Memoize-one: https://github.com/alexreardon/memoize-one#readme

4. Virtual Scroll (Windowing)

Virtual scrolling = rendering just enough content to fill the screen and continuously updating as the user scrolls.”

https://bvaughn.github.io/forward-js-2017

If you want to feel the difference between two apps where one uses virtual scroll vs. not using it. Compare Google Drive and Google Photos. In Drive you’d need a folder with several hundred items to get a good sense. Try guessing which one doesn’t use virtual scroll.

Useful Links

● React-Window:
https://react-window.now.sh

● Video — virtual-scroller: Let there be less (DOM) (Chrome Dev Summit 2018):
https://www.youtube.com/watch?v=UtD41bn6kJ0

●Angular cdk-virtual-scroll-viewport:
https://material.angular.io/cdk/scrolling/overview

●Vue Virtual Scroller
https://github.com/Akryum/vue-virtual-scroller

●Recycler List View:
https://github.com/Flipkart/recyclerlistview

5. Unused Code

This topic revolves around sending as little code as possible to the client. Especially during our app’s initial load. Your aim is to make it start and become interactive as soon as possible.

Check out concepts such as: Tree Shaking, code splitting, and polyfilling.

CDT (chrome devtools) very recently released a tool to inspect code usage (javascript & CSS)

code coverage report in chrome devtools

The red bars show the amount of code not being used. As developers we should consider splitting our code so the parts that aren’t mandatory for the app to function will be loaded lazily and as needed.

CDT coverage report

Useful Links

● Webpack Tree Shaking:
https://webpack.js.org/guides/tree-shaking/

● Making instagram.com faster (part 4):
https://instagram-engineering.com/making-instagram-com-faster-code-size-and-execution-optimizations-part-4-57668be796a8

● Find Unused JavaScript And CSS Code With The Coverage Tab:
https://developers.google.com/web/tools/chrome-devtools/coverage

● Polyfill.IO:
https://polyfill.io

6. Fonts

Beyond caching and pre-loading (see next topic) We can consider using the font-display: swap; CSS rule to make sure our app displays something until our fancy web font has a chance to load. Remember fonts are a relatively heavy resource and therefore could take a few seconds to load (depending on connection, etc.). The jump from blank screen to full of text might be jarring.

Useful Links

● font-display on MDN:
https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display

● A Comprehensive Guide to Font Loading Strategies
https://www.zachleat.com/web/comprehensive-webfonts/#preload

● The Web Font Loading Glossary:
https://www.zachleat.com/web/webfont-glossary/

● FontFaceSet.ready:
https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/ready

7. Service workers

Service workers can help us improve our application’s performance by caching images, HTML, javascript and CSS. It can make our application work offline and has a few more nifty features in store. Definitely worth reading about this more if you’d like to make your app feel more “native” on mobile devices.

Google’s Workbox makes it a lot easier to develop service workers without needing to start from scratch.

starbucks app uses workbox
definition of caching for images

It’s very easy for example to register a pattern for files to be stored in cache and how it should be accessed later on. For example using CacheFirst strategy, the image can be shown even if there’s no internet connection and while its cached we can save on a slower network request.

Useful Links

● Service workers primer:
https://developers.google.com/web/fundamentals/primers/service-workers/

● Service worker cookbook:
https://serviceworke.rs

● Google’s workbox:
https://developers.google.com/web/tools/workbox

● Gatsby offline plugin:
https://www.gatsbyjs.org/packages/gatsby-plugin-offline/

8. Media Optimization

There are many articles to read and write about media optimization. I recently gave a talk about performance at React Live in Amsterdam and devoted a section to this very topic.

In short, It’s important to keep in mind that most of the bytes we send down the wire to our clients are for images and more and more for videos. Web pages weight is mostly comprised of images. In many cases we send too much and our pages load slowly as a result.

https://httparchive.org/reports/state-of-images

Ensuring you’re only sending the necessary bytes while keeping an excellent visual experience is paramount and is something Cloudinary (the company I work for) does for a living.

Compare the following photo:

https://images.hdqwalls.com/download/the-witcher-henry-cavill-netflix-l2-3360x1890.jpg

With this one:

https://res.cloudinary.com/demo/image/fetch/q_auto,f_auto,w_900/https://images.hdqwalls.com/download/the-witcher-henry-cavill-netflix-l2-3360x1890.jpg

Can also be seen in the comparison below:

Consider a time when it becomes a part of your page’s layout. You only have 900px width to put the image in. If you load the first one (on the left) it weighs 860 KB while the second (on the right) only 41 KB. A twentieth of the size for the same visual effect. For a page with 20–30 images this reduction becomes enormously consequential. For your users and for your bottom line.

Another technique to consider is loading images lazily. This September (2019) Chrome shipped image lazy-loading as a native feature (the only one of the major vendors to support it currently). Images that the user doesn’t see will not be requested from the server. As the user scrolls closer they will be loaded.

And its as easy as adding one attribute to your img tag:

<img src="cat.jpg" loading="lazy" width="400" height="250"/>

This behavior can be mimicked in other browsers using javascript. react-lazyload is a good choice for React apps.

Useful Links

● Compress Images for Web and Boost Performance on Your Site:
https://cloudinary.com/blog/compress_images_for_web_and_boost_performance_on_your_site

● New Auto-Quality Setting for Content-Aware Video Compression:
https://cloudinary.com/blog/new_auto_quality_setting_for_content_aware_video_compression

● Native lazy-loading for the web:
https://web.dev/native-lazy-loading/

● Preload, Prefetch And Priorities in Chrome:
https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf

These were my 8 tips or rather topics with many tips between them. This should give you a good starting point to enter the vast and rich world of performance improvement for your front-end applications.

Hope it manages to shed a little light so you don’t feel completely in the dark!

Photo by Pietro De Grandi on Unsplash

--

--

Yoav Niran
Cloudinary Engineering Blog

I write. Code by day, science fiction by night. Check out my first novel at: https://whitecloudsbook.com