In the digital age, where users expect lightning-fast loading times and seamless browsing experiences, optimizing web performance is paramount for businesses and developers alike. One key aspect of this optimization lies in efficient resource fetching and prioritization. In this article, we delve into various techniques and strategies, including pre-connect and dns-prefetch, fetchpriority, prefetch, and preload, as well as the utilization of async and defer attributes in JavaScript execution.
By implementing these approaches, developers can significantly enhance page load times, improve user experience, and ultimately, bolster key performance metrics such as Largest Contentful Paint (LCP) and First Contentful Paint (FCP). Let's explore how each of these methods contributes to a faster and more responsive web.
preconnect
and dns-prefetch
Consider adding preconnec
t or dns-prefetch
resource hints to establish early connections to important third-party origins.
Modern browsers try their best to anticipate what connections a page will need, but they cannot reliably predict them all. We can give them a (resource) hint.
<link rel="preconnect">
informs the browser that your page intends to establish a connection to another origin, and that you'd like the process to start as soon as possible.
The preconnect
hint is best used for only the most critical connections.
For all the rest, use <link rel=dns-prefetch>
to save time on the first step(round trip), the DNS lookup, which usually takes around 20–120 ms.
Preconnecting is only effective for domains other than the origin domain, so you shouldn't use it for your site.
Only preconnect to critical domains you will use soon because the browser closes any connection that isn't used within 10 seconds. Unnecessary preconnecting can delay other important resources, so limit the number of preconnected domains and test the impact preconnecting makes.
If a page needs to make connections to many third-party domains, preconnecting all of them is counterproductive. The preconnect hint is best used for only the most critical connections. For all the rest, use <link rel=dns-prefetch> to save time on the first step, the DNS lookup, which usually takes around 20–120 ms.
Browser support for dns-prefetch
is slightly different from preconnect support, so dns-prefetch can serve as a fallback for browsers that don't support preconnect
.
Using dns-prefetch and preconnect allows sites to reduce the amount of time it takes to connect to another origin. The ultimate aim is that the time to load a resource from another origin should be minimized as much as possible.
Where Largest Contentful Paint (LCP) is concerned, it is better that resources are immediately discoverable, since LCP candidates are crucial parts of the user experience.
fetchpriority
Fetchpriority
is an attribute that allows you to hint at the relative priority of a resource (high or low). Priority Hints can help optimize the Core Web Vitals.
You can provide a Priority Hint using the fetchpriority
HTML attribute. You can use the attribute with link
, img
, script
, and iframe
tags. The attribute allows you to specify the priority for resource types such as CSS, fonts, scripts, images, and iframe when downloaded using the supported tags.
The fetchpriority attribute accepts one of three values:
high
: This is used when the resource is considered a high priority. The browser is instructed to prioritize it, given that its heuristics don't hinder this.
low
: This is used when the resource is considered a low priority. The browser is instructed to deprioritize it if its heuristics allow.
auto
: This is the default value used when there is no preference. The browser decides the appropriate priority.
<img src="lcp-image.jpg" fetchpriority="high">
<link rel="preload" href="/js/script.js" as="script" fetchpriority="low">
<script>
fetch('https://example.com/', {priority: 'low'})
.then(data => {
// Trigger a low priority fetch
});
</script>
The fetchpriority
attribute is a hint and not a directive. The browser will try to respect the developer's preference. It is also possible that the browser will apply its preferences for resource priority as deemed necessary in case of conflicts.
You can specify fetchpriority="high"
to boost the priority of the LCP or other critical images.
<img src="lcp-image.jpg" fetchpriority="high">
prefetch
Adding <link rel=prefetch>
to a web page tells the browser to download entire pages or some of the resources (like scripts or CSS files), that the user might need in the future.
The prefetch
hint consumes extra bytes for resources that are not immediately needed, so this technique needs to be applied thoughtfully; only prefetch resources when you are confident that users will need them.
<link rel="prefetch" href="/articles/" as="document">
Prefetching images can significantly lower LCP times for LCP image elements.
Prefetching stylesheets can improve both FCP and LCP, as the network time to download the stylesheet will be eliminated. Since stylesheets are render-blocking, they can reduce LCP when prefetched. In cases where the subsequent page's LCP element is a CSS background image requested via the background-image property, the image will also be prefetched as a dependent resource of the prefetched stylesheet.
Prefetching JavaScript will allow the processing of the prefetched script to occur much sooner than if it were required to be fetched by the network first during navigation. This can have an effect on responsiveness metrics such as First Input Delay (FID) and Interaction to Next Paint (INP).
In cases where markup is rendered on the client via JavaScript, LCP can be improved through reduced resource load delays, and client-side rendering of markup containing a page's LCP element can occur sooner.
If you're using code-splitting, you can apply prefetch to routes or components that are not immediately necessary but will likely be requested soon.
<link rel="prefetch" as="script" href="1.bundle.js">
import(/* webpackPrefetch: true */ 'Pages/Step1/Step2');
preload
By preloading a certain resource, you are telling the browser that you would like to fetch it sooner than the browser would otherwise discover it because you are certain that it is important for the current page.
<link rel="preload" as="script" href="critical.js">
Link: </css/style.css>; rel="preload"; as="style"
Supplying the as
attribute helps the browser set the priority of the prefetched resource according to its type, set the right headers, and determine whether the resource already exists in the cache. Accepted values for this attribute include: script
, style
, font
, image
, and others.
Pacifico font is defined in the stylesheet with a @font-face
rule. The browser loads the font file only after it has finished downloading and parsing the stylesheet.
Pacifico font is preloaded, so the download happens in parallel with the stylesheet.
Fonts defined with @font-face rules or background images defined in CSS files aren't discovered until the browser downloads and parses those CSS files. Preloading these resources ensures they are fetched before the CSS files have been downloaded.
Because browsers don't execute preloaded files, preloading is useful to separate fetching from execution which can improve metrics such as Time to Interactive. Preloading works best if you split your JavaScript bundles and only preload critical chunks.
Preloading has a powerful effect on Largest Contentful Paint (LCP) when it comes to fonts and images, as both images and text nodes can be LCP candidates. Hero images and large runs of text that are rendered using web fonts can benefit significantly from a well-placed preload hint and should be used when there are opportunities to deliver these important bits of content to the user faster.
However, you want to be careful when it comes to preloading—and other optimizations! In particular, avoid preloading too many resources. If too many resources are prioritized, effectively none of them are. The effects of excessive preload hints will be especially detrimental to those on slower networks where bandwidth contention will be more evident.
async
or defer
to Execute the CodeJavaScript execution is parser blocking. This means when the browser encounters a script it must pause DOM construction, hand this over to the JavaScript engine, and allow script execution before proceeding with DOM construction.
The async
and defer
attributes tell the browser that it may go on parsing the HTML while loading the script in the background, and then execute the script after it loads. This way, script downloads don't block DOM construction and page rendering. The result is that the user can see the page before all scripts have finished loading.
<script async src="script.js">
<script defer src="script.js">
The async and defer attributes change this behavior.
async
, the browser downloads the script asynchronously while it continues to parse the HTML document. When the script finishes downloading, parsing is blocked while the script executes.
defer
, the browser downloads the script asynchronously while it continues to parse the HTML document. The script doesn't run until the parsing is complete.
Proper configuration of high and low-priority scripts can give more sources to the parser to render the HTML while some of the scripts are being loaded as third-party scripts will not block the parser. And the browser is able to render the page as soon as possible.