Prefetch & preconnect-dns priority
Preconnect and prefetch-dns are both ways which you can ask your browser to do a DNS lookup and connection before you need any resources from that domain, but it helps shave time off the critical rendering path. This article looks at what difference the order of the tag makes. The short answer is none.
The concept
The very first thing that occurs when you request a page, let’s say this page at https://responsivedesign.is/articles/prefetch-preconnect-dns-priority/, is that your browser needs to work out where responsivedesign.is is located — known as a DNS handshake. If you look at a Waterfall Chart you’ll notice the very first part of any request is aqua green and represents the DNS lookup.
The concept around preconnect and prefetch-dns is that the DNS lookup happens as soon as possible, long before there is any reference to a resource on that particular domain. By doing this you can shave off time when you do get around to requesting the resource (preconnect does a little more than that, but more on that later).
How much time? Well in the example Waterfall chart above the DNS lookup times are
150 ms —//cdnjs.cloudflare.com
185 ms —//production-assets.codepen.io
167 ms — //s3-us-west-2.amazonaws.com
A hundred and a bit milliseconds each, but when you combine them and you get to 502ms which half a second of time that you are able to move outside of the critical loading path and thus gain half a second performance improvements.
Difference between dns-prefetch & preconnect
The difference between dns-prefetch and preconnect is dns-prefetch will only do the DNS lookup, while preconnect will do the DNS lookup, TLS negotiation, and the TCP handshake. This means that it avoids an additional 2 RTT once the resource is ready to be downloaded.
When it came to my tests on Web Page Test though it only seemed to result in the DNS lookup and I haven’t been able to account for that. It could be that support for dns-prefetch is much larger than support for preconnect. I assume that the Chrome version I was using on WPT didn’t support the feature fully but still provided the DNS lookup.
The question — does order priority matter?
The whole reason why this article came into existence was because I was reviewing the Victoria and Albert Museum Website for the examples section on this site. During the review I noticed that the site was using the below snippet to start the DNS lookup early and save time on future requests.
<link rel=”dns-prefetch” href=”//vanda-production-assets.s3.amazonaws.com” />
This was done within the <head> tags but the site also used a <style> tag in the head to declare the page background-image in a series of media queries. These background-image declarations were actually placed before the dns-prefetch tag. This caused me to question which would fire first?
Would the browser see an image URL and immediately begin to download the image asset, thus requiring the DNS lookup before reaching the dns-prefetch tag
Would the browser parse everything in the HTML document before invoking any requests
Testing the order priority
To test this I created a series of Code Pens check when the DNS lookup would occur across five different scenarios. Each of the scenarios were then tested through Web Page Test using a chrome browser on a Fast 3G connection. I chose that connection because I assumed any differences in the request timings would show up best over a slower mobile connection (although I didn’t go as far as 2G)
The code pens all had a style tag in the header setting a background-image on the body, and the difference between them was the type and location of the ‘pre’ DNS lookup request, see these below
dns-prefetch after styles
dns-prefetch before styles
preconnect after styles
preconnect before styles
No preconnect prefetch
No preconnect prefetch
With no reference to any performance enhancing elements you can see how a resource would usually be requested, notice the DNS lookup adding to the critical path.
<style>
body {background-image:url(‘https://s3-us-west-2.amazonaws.com/s.cdpn.io/7635/Ayers-Rock-Australia.jpg’)}
</style>
Critical load path when no prefetch/preconnect of the DNS is included in the <head>
dns-prefetch after styles
<style>
body {background-image:url(‘https://s3-us-west-2.amazonaws.com/s.cdpn.io/7635/Ayers-Rock-Australia.jpg’)}
</style>
<link href=”https://s3-us-west-2.amazonaws.com” rel=”dns-prefetch”>
As you can see from the image of the waterfall chart below that even though the background-image is declared before the link tag for the dns-prefetch the DNS lookup happens immediately after the HTML document has been parsed, and in parallel with the other DNS lookup for the first resource that Code Pen includes (normalise.css from //cdnjs.cloudflare.com.
Critical load path when preconnect is included in the <head> after the <style> tag
dns-prefetch before styles
As you would expect, if the handshake happens when we want it to when declared after the image is works the same way when it’s declared before.
<link href=”https://s3-us-west-2.amazonaws.com” rel=”dns-prefetch”>
<style>
body {background-image:url(‘https://s3-us-west-2.amazonaws.com/s.cdpn.io/7635/Ayers-Rock-Australia.jpg’)}
</style>
Critical load path when dns-prefetch is included in the <head> before the <style> tag
preconnect after styles
In this test I wanted to see the overall difference between the two approaches and see how much time could be saved by performing all three initial connections up front. Unfortunately there was no difference which I need to look at further.
<style>
body {background-image:url(‘https://s3-us-west-2.amazonaws.com/s.cdpn.io/7635/Ayers-Rock-Australia.jpg’)}
</style>
<link href=”https://s3-us-west-2.amazonaws.com” rel=”preconnect” crossorigin>
Critical load path when dns-prefetch is included in the <head> after the <style> tag
preconnect before styles
This test performed as expected with regards to the DNS lookup happening first, but again it didn’t complete the TCP or TLS handshakes.
<link href=”https://s3-us-west-2.amazonaws.com” rel=”preconnect” crossorigin>
<style>
body {background-image:url(‘https://s3-us-west-2.amazonaws.com/s.cdpn.io/7635/Ayers-Rock-Australia.jpg’)}
</style>
Critical load path when preconnect is included in the <head> before the <style> tag
Conclusion
As you see it doesn’t matter where the declaration of the link tag occurs in the <head>, as long as it is there it will perform the DNS lookup ahead of time and therefore save your users time when browsing your site.
This is certainly something that you should be including for any domains that are outside your own site, in particular CDN’s for your images, font locations (like Google Fonts) or any external JS you might have on the site.