DEV Community

Cover image for Fine-Tuning Resource Priorities: The Power of fetchpriority
Leapcell
Leapcell

Posted on

Fine-Tuning Resource Priorities: The Power of fetchpriority

Cover

Background

Preloading allows key content to be loaded before the entire webpage finishes loading, providing users with a better experience and reducing waiting time. However, in some cases, we also need to further categorize the priority of preloaded resources. Since preloading alone cannot fully control resource prioritization, the fetchpriority attribute was introduced to supplement it.

Objectives

  • Influence the priority of resource retrieval.
  • Supplement the loading order of preloaded resources.

Priority indicates the relative importance of resources to the browser. Proper prioritization ensures optimal loading, thereby enhancing the web user experience.

Resource Priority

When a browser begins parsing a webpage and downloading images, JavaScript, CSS, and other resources, it assigns each resource a fetchpriority flag, representing its download priority.

The order in which resources are downloaded depends on this priority flag, which is determined by multiple factors:

  • Different priorities are assigned to CSS, fonts, scripts, images, and third-party resources.
  • The location or order of resources within the document affects priority.
  • Preloading resource hints help browsers discover resources faster, allowing them to load before the document finishes parsing, thus influencing priority.
  • The async or defer attributes of scripts impact priority calculations.

Browsers download resources in the order they are discovered. You can check the assigned priorities in DevTools Network:

Screenshot

However, the default priority assigned to resources is not always optimal in every scenario.

When to Use Priority Hints

Technical Use Cases:

  • Multiple above-the-fold images with different priority needs: In an image carousel, only the first visible image should have the highest priority.
  • Images within the viewport initially marked as low priority: When Chrome detects they are visible after layout completion, it automatically raises their priority, potentially delaying their loading. Using priority hints allows them to load earlier at a higher priority.
  • Scripts marked with async or defer: These scripts are assigned a "low" priority. However, certain scripts that are crucial for user experience may require a priority boost while still maintaining asynchronous loading.
  • CSS and fonts: Browsers assign high priority to CSS and fonts by default, but not all are equally important. Priority hints can help lower the priority of less critical resources.
  • Fetching resources with fetch(): Browsers assign high priority to fetch() requests by default. In some cases, not all requests should have high priority. Background API calls can be marked as low priority, while interactive API calls can be high priority.
  • Limited network bandwidth environments: Prioritization gains become particularly significant when resources compete for available bandwidth.

The fetchpriority Attribute

The fetchpriority attribute accepts three values:

  • high: The resource is deemed important and should be prioritized by the browser.
  • low: The resource is less important and should have a lower priority.
  • auto: The browser determines the priority based on its default logic.

Usage Examples:

<!-- This above-the-fold image is not important, so we lower its priority -->
<img
  src="/images/in_viewport_but_not_important.svg"
  fetchpriority="low"
  alt="I'm an unimportant image!"
/>

<!-- We want to initiate an early fetch for a resource but deprioritize it -->
<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 third-party contents of this iframe can load with low priority -->
<iframe src="https://example.com" width="600" height="400" fetchpriority="low"></iframe>
Enter fullscreen mode Exit fullscreen mode

Boosting LCP Image Priority

For example, on the Google Flights webpage, one of the primary causes of a poor Largest Contentful Paint (LCP) score is the slow loading of its background image. We can use the fetchpriority attribute to raise its loading priority:

<img src="lcp-image.jpg" fetchpriority="high" />
Enter fullscreen mode Exit fullscreen mode

With the priority set to high, the LCP improves from 2.6 seconds to 1.9 seconds.

Lowering the Priority of Above-the-Fold Images

We can use the fetchpriority attribute to lower the priority of less critical above-the-fold images, such as non-visible images in a carousel:

<ul class="carousel">
  <img src="img/carousel-1.jpg" fetchpriority="high" />
  <img src="img/carousel-2.jpg" fetchpriority="low" />
  <img src="img/carousel-3.jpg" fetchpriority="low" />
  <img src="img/carousel-4.jpg" fetchpriority="low" />
</ul>
Enter fullscreen mode Exit fullscreen mode

Lowering Preloaded Resource Priority

To prevent preloaded resources from competing with other critical resources, we can explicitly lower their priority:

<!-- Lower priority only for non-critical preloaded scripts -->
<link rel="preload" as="script" href="critical-script.js" />
<link rel="preload" href="/js/script.js" as="script" fetchpriority="low" />

<!-- Preload CSS without blocking other resources -->
<link
  rel="preload"
  as="style"
  href="theme.css"
  fetchpriority="low"
  onload="this.rel='stylesheet'"
/>
Enter fullscreen mode Exit fullscreen mode

Adjusting Script Priority

If a page contains important interactive scripts that should not block other resources, they can be marked as high priority while still loading asynchronously:

<script src="async_but_important.js" async importance="high"></script>
Enter fullscreen mode Exit fullscreen mode

If a script depends on specific DOM elements, it cannot be marked as async. However, if it is not essential for above-the-fold rendering, we can lower its priority:

<script src="blocking_but_unimportant.js" importance="low"></script>
Enter fullscreen mode Exit fullscreen mode

Adjusting Fetch Priority

By default, browsers execute fetch() requests with high priority. We can lower the priority of non-critical data requests:

// Important validation data (default high priority)
let authenticate = await fetch('/user');

// Less important content data (suggested low priority)
let suggestedContent = await fetch('/content/suggested', { priority: 'low' });
Enter fullscreen mode Exit fullscreen mode

Considerations

Priority hints can improve performance in specific use cases, but there are a few things to keep in mind:

  • The fetchpriority attribute is a hint, not a directive. The browser will attempt to respect developer preferences but may override them based on its internal prioritization logic.
  • Do not confuse priority hints with preloading. They serve different purposes:

    • Preloading forces resource fetching, whereas priority hints are only suggestions.
    • Preloading is easier to observe and measure.
  • Priority hints complement preloading by providing finer-grained control over priority levels. If an LCP image is preloaded at the top of a page, a high priority hint may not yield significant benefits. However, if preloading occurs after less important resources, a high priority hint can improve LCP. For critical CSS background images, use fetchpriority="high".

  • CDNs do not have a unified implementation of HTTP/2 prioritization.

Even if a browser conveys priority hints, a CDN may not respect the requested priority order.

Additional Notes

The importance Attribute

The importance priority hint was first introduced as an experimental feature in Chrome in 2018, then revisited in 2021. As part of the web standards process, it has since been replaced:

  • In HTML, the attribute has been renamed to fetchpriority.
  • In JavaScript, it has been replaced with the priority option.

We are Leapcell, your top choice for hosting backend projects.

Leapcell

Leapcell is the Next-Gen Serverless Platform for Web Hosting, Async Tasks, and Redis:

Multi-Language Support

  • Develop with Node.js, Python, Go, or Rust.

Deploy unlimited projects for free

  • pay only for usage — no requests, no charges.

Unbeatable Cost Efficiency

  • Pay-as-you-go with no idle charges.
  • Example: $25 supports 6.94M requests at a 60ms average response time.

Streamlined Developer Experience

  • Intuitive UI for effortless setup.
  • Fully automated CI/CD pipelines and GitOps integration.
  • Real-time metrics and logging for actionable insights.

Effortless Scalability and High Performance

  • Auto-scaling to handle high concurrency with ease.
  • Zero operational overhead — just focus on building.

Explore more in the Documentation!

Try Leapcell

Follow us on X: @LeapcellHQ


Read on our blog

Top comments (0)