The pre-loader (also known as the speculative or look-ahead pre-parser) may be the single biggest improvement ever made to browser performance.
During their implementation Mozilla reported a 19% improvement in load times, and in a test against the Alexa top 2,000 sites Google found around a 20% improvement.
It’s not a new browser feature but some seem to believe it’s Chrome only and yet others suggest it’s “the most destructive ‘performance enhancement’ there’s ever been”!
So what is the pre-loader and how does it improve performance?
How browsers used to load web pages
Web pages are full of dependencies – a page can’t start rendering until the relevant CSS has downloaded, then when a script is encountered the HTML parser pauses until the script has executed (of course if the script is external it needs to be downloaded too).
Let’s consider how a browser might load a page:
First the HTML is downloaded and the browser starts parsing it. It finds a reference to an external CSS resource and fires off a request to download it.
The browser can carry on parsing the HTML while the CSS is downloading but then it finds a script tag with an external URL, now (unless the script has
async
ordefer
attributes) it must wait until the script has downloaded and executed.Once the script has downloaded and executed, the browser can continue parsing the HTML, when it finds non-blocking resources such as images it will request them and carry on parsing, but when it finds a script it must stop and wait for the script to be retrieved and executed.
Although a browser is capable of making multiple requests in parallel, one that behaved like this often wouldn't be downloading any resources in parallel with a script.
This is how browsers used to behave and using Curzillion by Steve Sounders we can create a test page that demonstrates this in IE7.
The test page has two stylesheets followed by two scripts in the head, then in the body it has two images, a script and finally another image.
The waterfall makes it easy to see parallel downloads stop while a script is being downloaded.
Waterfall of Cuzillion generated test page in IE7
If browsers still worked like this then pages would be slower to load as every time a script was encountered the browser would need to wait for the script to be downloaded and executed before it could discover more resources.
How the pre-loader improves network utilisation
Internet Explorer, WebKit and Mozilla all implemented pre-loaders in 2008 as a way of overcoming the low network utilisation while waiting for scripts to download and execute.
When the browser is blocked on a script, a second lightweight parser scans the rest of the markup looking for other resources e.g. stylesheets, scripts, images etc., that also need to be retrieved.
The pre-loader then starts retrieving these resources in the background with the aim that by the time the main HTML parser reaches them they may have already been downloaded and so reduce blocking later in the page.
(Of course if the resource is already in the cache then the browser won’t need download it)
Repeating the previous test with IE8 shows other resources are now downloaded in parallel with scripts, delivering a huge performance improvement for this test case: 7s vs 14s.
Waterfall of Cuzillion generated test page in IE8
Pre-loader behaviour varies between browsers and is still an area of experimentation, some browsers seem to have naive implementations where they download the resources in order of discovery but other browsers prioritise the downloads, for example Safari gives stylesheets that don’t apply to the current viewport a low priority, Chrome schedules scripts (even those at the foot of a page) with a higher priority than most of the images on the page.
The prioritisation mechanisms aren’t well documented (you can read the source for some browsers!) but if you want to get a better understanding of what they can do, James Simonsen wrote some excellent notes about the approaches they’re trying in Chrome.
Pre-Loader Gotchas
Pre-loaders extract URLs from markup and don’t / cannot execute javascript so any URLs inserted using javascript aren’t visible to it and the download of these resources will be delayed until the HTML parser discovers and executes the javascript that loads them.
There are cases where inserting resources using javascript can also trip up some pre-loaders.
I came across an answer on Stack Overflow suggesting javascript should be used to insert a link to either a mobile or desktop stylesheet depending on browser width: