Testing priority hints with WebPageTest
Back in January 2019 the Chrome team published an Intent to Experiment: Priority Hints message to the blink developers Google group. This set out a plan to start an origin trial to allow developers to experiment with this new web platform feature and give feedback before eventual rollout across all origins.
Unfortunately Priority Hints are currently on hold as the Chrome team weren’t able to to see statistically significant performance wins with the current design. So does that mean you can’t play with this experimental web platform feature now? No, not at all! Read on to find out more how you can still experiment with it using both your browser, and more interestingly, WebPageTest with Cloudflare Workers!
What are priority hints?
Lets very briefly look at what priority hints are and their expected usage. So priority hints are a way for developers to tell a browser the relative priority of resources on a page. A developer can then increase or decrease the priority of an asset depending on how they judge it’s priority in the page load process. So for example:
<!-- The main image is in the viewport, so considered important by the browser, but we disagree --> <img src="/images/hero-image.png" importance="low" alt="Main hero image, but considered unimportant"> <!-- we want the browser to know to fetch this script, but don't prioritise over other important assets --> <link href="/js/required-later.js" importance="low" rel="preload" as="script"> <!-- script set to async so it won't block the thread while JS is fetched but we consider this script to be important so bump its priority for download --> <script src="/js/async-script.js" importance="high" async></script>
Now of course you need to be careful when changing priorities. If you bump one asset’s priority level, you are lowering the priority of another. Or if you bump all assets to
high, then really you have no prioritisation at all! There’s a very important note to be made at this point. These are hints to the browser. They aren’t instructions. Prioritisation in the browser is very complex and it will use heuristics to determine how best to load a page. These hints are a developer’s way to give it more information for consideration. But ultimately it is up to the browser if it actually decides to use the hint for network prioritisation. It may simply choose to ignore them and continue as is.
But one of the interesting use cases for priority hints is not boosting an assets priority with the
high value, it’s actually lowering an assets priority using
low. By doing so you are giving other assets on a page network priority. So say for example you had an image at the top of your page that you know will be in the main viewport. Browser heuristics state that this will automatically be a high priority asset. But what if that image doesn’t actually add value to a user’s journey. It’s a ‘nice to have’ (eventually), but concentrate on the rest of the page before loading it. That’s just a very simple example of where this functionality could be useful.
There’s a really informative blog post: “Get Ready for Priority Hints” by Jeremy Wagner and Yoav Weiss which goes into priority hints in much more detail.
So how do I use them?
Okay so enough waffle already, how do you try them today? It’s actually really simple, as they are sitting behind the ‘Experimental Web Platform features’ in Chrome flags (chrome://flags/#enable-experimental-web-platform-features).
In Chrome you can either enable the ‘Experimental Web Platform features’ flag manually, or use the command line interface to fire up a Chrome window with it already enabled. On OSX you simply enter this command into the terminal:
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --enable-experimental-web-platform-features
Doing this via WebPageTest is just as simple as above. Just make sure you are running a test using a Chromium browser and enter
--enable-experimental-web-platform-features into the ‘command line custom options’ under the ‘Chromium’ tab (see below):
The Chromium browser running the test will now have priority hints enabled (assuming it’s based on a build after M73).
Are priority hints enabled?
So how do you know if priority hints are enabled? Well I’ve created some incredibly simple demo pages that will allow you to test to see if they are. The pages contain a selection of images with their priorities modified using the
importance attribute. You will quickly be able to spot if priority hints are enabled by looking at the network tab in DevTools and making sure the ‘Priority’ tab is visible.
In the image below, priority hints aren’t enabled. All images get a
high priority and the preloaded image gets a
Now lets see what happens when the experimental flag (and client hints) and enabled:
The above image looks very different. Each of the images has a priority set depending on the image name (mirrored with the
importance attribute) and the preload has been forced to be
high priority. Note that images with
importance="auto" return the default priority determined by the browser heuristics. A very unscientific and simple demo, but it allows you to test to see if client hints have been enabled.
Using it in the wild
So you may be asking: “Why would I be adding the
importance attribute to my website when no browsers actually support them!”. And for that I completely agree, that’s not a good idea. But that doesn’t mean we can’t test in “production environments”. It’s time to roll out our favorite new friend, Cloudflare Workers (CFW).
I’ve blogged before about how I’ve started to use CFW to experiment with web performance changes. And since priority hints are easily applied using the
importance attribute they seem like the perfect candidate for the HTMLRewriter runtime API. But what’s even better is we can easily combine a CFW with WebPageTest. By doing so, we can experiment with changing our production environment and measure the difference in performance the
importance attributes would make to page loading.
Cloudflare Workers setup
With this setup I’m piggybacking off the code Andy Davies lists on his blog post.
Preloading Print CSS files
In this very simple example we take ‘IDLE’ priority CSS files (print stylesheets) and bump them up the priority order by preloading them. It’s then possible to tweak the priority of the preload using the
importance attribute. Note: This is a completely contrived example to show the attributes in action. I wouldn’t recommend doing this in practice!
Without preloading our print style sheets have an ‘IDLE’ priority and are seen at requests 11 and 12:
Now let’s use a Cloudflare Worker to inject a
<link rel="preload"> right after the opening
In the example what is seen is very predictable. Our print stylesheets have been bumped up the network request order, now sitting at request 2 and 3. Also the priority for these CSS files is now set to
Preloaded CSS with priority hints
Now let’s enable priority hints in Chrome and modify the preloads to add the
In the example above we still have the print stylesheets sitting at requests 2 & 3, but the important difference is the priority of this preload has been set to
LOWEST. We have successfully given the browser a hint that this preload exists but isn’t important. Now this is such a simple page and example that the change actually has no effect on the performance of the page (other than slowing it down slightly because we are preloading print CSS!). But it does show how easy it is to modify a page’s HTML using a Cloudflare Worker and experiment with priority hints.
If you are interested in the code used to create this very simple example I’ve dropped it all into a gist here.
There’s a file with
vendor.js in the filename that comes in at 170 KB in size. The file looks to contain some helper libraries for classnames, Brightcove video, and a production version of React v16.12.0. Note: If any developers from Nike are reading this, you look to be including another version of React later in the page load (v16.13.0), so that’s a pretty good optimisation to look at right there!
By default this
vendor.js file is given a medium priority, with a weight of 220. Note: Very roughly speaking, the higher the weight value, the higher the priority. With a standard
preload this file downloads at request number 5 in the waterfall, as seen below:
But as mentioned above with priority hints we have the ability to give the browser a hint that this preload should have a lower priority. So using our Cloudflare Worker to modify the HTML lets see what happens when we add
importance="low" to this single preload. The resulting waterfall can be seen below:
Priority weight drops from 220 to 147 and from request 5 to 17.
Next on the list is the preload containing
Again we use priority hints to add
importance="low" and investigate what happens:
Priority weight drops from 220 to 147 and from request 6 to 16.
So we’ve dropped the priority of each preload individually, so let’s see what happens when we do it for both at the same time:
With both preloads having
importance="low" added, we see the following:
vendor.jsweight drops from 220 to 147. Request number drops from 5 to 15.
client.jsweight drops from 220 to 147. Request number drops from 6 to 18.
So enough of looking at random waterfalls. We can see that the priority hints are working as expected. But what really matters is the performance a user sees. We now have 4 tests we can compare using WebPageTest:
- Baseline: No HTML modifications, priority hints enabled but not used. Cloudflare Worker used as a basic proxy.
- Vendor.js file preload set to
low: HTML modification to a single preload, priority hints enabled and used.
- Client.js file preload set to
low: HTML modification to a single preload, priority hints enabled and used.
- Both preloads set to
low: HTML modification to a both preloads, priority hints enabled and used.
WebPageTest outputs a very interesting filmstrip and set of graphs:
In the image above we see the baseline at the top, and both now low priority preloads at the bottom. The difference in performance is quite striking. Pixels are being rendered to the screen a whole 2 seconds faster. Not bad for a 3G Fast connection (on Chrome desktop)!
Next let’s take a look at the timing information graph:
The most important difference for me is the render metrics. Comparing the baseline to both preloads being set to
- Speed Index changes from 5,630 to 5,172, or an improvement of 8%.
- First Contentful Paint and First Meaningful Paint change from 3,650 to 1,972, or an improvement of 46%.
- Visually Complete from 10,900 to 6,800, or an improvement of 38%.
- Total Blocking Time from 564 to 328, or an improvement of 39%.
Now it isn’t all positive, we do see certain metrics get worse:
- Time to Interactive changes from 6,686 to 8,392 or a regression of 26%.
- Largest Contentful Paint changes from 6,737 to 6,949, or a regression of 3%.
- Load Time (Fully Loaded) changes from 13,354 to 13,487, or a regression of 1%.
The visually progress graph really shows the difference in the way the page is rendered for each test:
The green line where both preloads are set to
If you are interested in the worker code for this experiment it can be found in this gist.
Looking for feedback
So although priority hints are currently on hold, the Chrome team are still looking for feedback for future iterations. There are a number of issues open in the github repo with feedback from the community and Addy Osmani has also stated the team are interested in how much control developers would like over resource loading. Is it:
- More to do with “when” (e.g.
- High-level influence (e.g.
- Granular (modulo H/2 priority gotchas) (e.g
The team have seen priority hints come in most useful when there’s demonstrable network contention between resources and you want to re-order requests for more optimal use of available bandwidth (e.g. using
importance="low" to mark certain resources less important, so use bandwidth elsewhere).
In this post we’ve looked over what priority hints are, their current status, and how to enable and experiment with them on your local browser. Taking this one step further you can also test on live sites using a Cloudflare Worker and WebPageTest. It just shows what a powerful combination these two tools are when used together!
I’m personally a fan of priority hints and I’d love to see them being developed in the future. I like the idea that I have some influence over the priority of assets loading in a page. The web is such a varied medium with so many edge cases that it seems impossible (to me anyway) for browser heuristics to cover all of these issues automatically. So giving developers the means to steer a browser in a certain direction sounds like a win to me.
So if you’ve spotted an issue that you think could be solved using priority hints, why not try them out in production using a Cloudflare Worker and WebPageTest and see what results come back. I’m sure the Chrome team would be very interested in hearing about it!
- 21/02/21: Initial post published. Thanks to Addy Osmani for the input around feedback and where the team have seen wins with priority hints.
- 22/02/21: Minor change related to what ‘weight’ really means in terms of prioritisation in Chrome. It’s a massive oversimplification that I plan to address in the future with a new section. Thanks to Robin Marx for highlighting!