Opening a page in the Google Cloud Console always takes a long time.
Here are some metrics I collected on a high-end 2018 MacBook Pro on a UK-based Gigabit internet connection.
|Cloud Functions||4.2 MB||15.7 MB||5.3s||6.7s||8.1s|
|Compute Engine||4.5 MB||15.1 MB||6.5s||6.7s||8.1s|
|Cloud Storage||4.3 MB||16.2 MB||6.2s||6.5s||8.2s|
This article will take a closer look at the page load process of the Google Cloud Functions page, and examine how it could be sped up.
You can use these strategies to investigate and improve the performance of the apps you're working on.
Loading the HTML document
- routemap 21 KB (103 KB uncompressed)
- core,pm_ng1_bootstrap 1.3 MB (4.8 MB uncompressed)
These files don't take too long to download, but running the code freezes the UI for a while. The spinner SVG becomes stuck at this point, until it's replaced by a skeleton UI for Google Cloud Console page.
- Parsing (done lazily at first, and then as needed later on)
- Compilation (also happens lazily)
- Initialization – the browser runs module initialization code, i.e. code that runs when loading a module rather than when calling one of its functions
- Running core app code – renders the application using the initialized modules
For the whole Google Cloud page, just parsing the source code takes 250ms, and compilation takes another 750ms (not including the 113 ms spent on "Compile Script").
The initial render of the Angular app takes about 1s.
Eventually we start to see a new spinner.
Loading page bundles
Making a lot of separate requests isn't actually a problem though – it can improve performance by increasing the likelinhood of cache hits, and splitting up bundles makes it easy to load only necessary code.
After loading the first set up bundles the app starts making fetch requests and loads 3 more bundles at a total size of 6 MB.
When loading the page on my normal network the requests all kind of blurred together and it was hard to see which requests were sequential. So this screenshot shows the request chart on a throttled connection.
Loading the list of Cloud Functions
The request loading the list of Cloud Functions takes about 700ms. But it doesn't start as soon as the bundles are loaded, in part because there's a
testIamPermissions request that needs to finish first.
As a result the CPU ends up being idle for half a second – this time could be used better if the request started sooner.
Finally the app re-renders and we get the list of Cloud Functions we wanted to see.
Detecting unused code in Chrome DevTools
Chrome DevTools has a code coverage tool tracks which parts of the code actually run on the current page. This can help identify code that doesn't have to be loaded.
Moving configuration into JSON
A good amount of the code actually consists of configuration objects. For example, this 200 KB object with 4997 keys.
Loading this as a JSON string with
Ideally the app wouldn't need to load the full list on the client, but this would be harder to implement.
Reduce code duplication
The same seems to apply to a bunch of UI components, like this one.
Prioritize primary content
But the initial bundle also contains secondary content, like the complex navigation sidebar. This menu becomes functional before the main page content is loaded, but it should only be loaded after the primary content.
Google Cloud already does this in some cases. For example, the page initially renders a simpler version of the header and then loads more complex features later on.
Downloading large amounts of code can hurt performance on slow connections, but due to compression and caching CPU processing often has a greater impact.
If you want to track the performance of your website, including logged-in pages, give DebugBear a try.