Fetch Priority API로 리소스 로드 최적화

Fetch Priority API는 브라우저에 대한 리소스의 상대적 우선순위를 나타냅니다. 이를 통해 최적의 로드를 사용 설정하고 Core Web Vitals를 개선할 수 있습니다.

브라우저 지원

  • Chrome: 102.
  • Edge: 102.
  • Firefox: 132.
  • Safari: 17.2.

소스

브라우저가 웹페이지를 파싱하고 이미지, 스크립트, CSS와 같은 리소스를 검색하고 다운로드하기 시작하면 최적의 순서로 다운로드할 수 있도록 가져오기 priority를 할당합니다. 리소스의 우선순위는 일반적으로 리소스의 유형과 문서 내 위치에 따라 달라집니다. 예를 들어 시점 내 이미지의 우선순위는 High일 수 있고 <head>에서 <link>를 사용하여 조기에 로드된 렌더링 차단 CSS의 우선순위는 Very High일 수 있습니다. 브라우저는 잘 작동하는 우선순위를 할당하는 데 능숙하지만 모든 경우에 최적은 아닐 수 있습니다.

이 페이지에서는 Fetch Priority API와 fetchpriority HTML 속성을 설명합니다. 이 속성을 사용하면 리소스의 상대적 우선순위 (high 또는 low)를 암시할 수 있습니다. Fetch Priority는 Core Web Vitals를 최적화하는 데 도움이 될 수 있습니다.

요약

가져오기 우선순위가 도움이 되는 몇 가지 주요 영역:

  • 이미지 요소에 fetchpriority="high"를 지정하여 LCP 이미지의 우선순위를 높이면 LCP가 더 빨리 발생합니다.
  • 현재 가장 일반적인 해킹 (async 스크립트에 <link rel="preload"> 삽입)보다 더 나은 시맨틱을 사용하여 async 스크립트의 우선순위를 높입니다.
  • 이미지와의 시퀀싱을 개선하기 위해 뒷부분 스크립트의 우선순위를 낮춥니다.
Google 항공편 홈페이지의 두 테스트를 비교하는 필름 스트립 뷰 하단에서 가져오기 우선순위가 사용되어 히어로 이미지의 우선순위가 높아져 LCP가 0.7초 감소했습니다.
Google 항공편 검색 테스트에서 가져오기 우선순위로 Largest Contentful Paint가 2.6초에서 1.9초로 개선되었습니다.

이전에는 개발자가 preloadpreconnect를 사용하여 리소스 우선순위에 미치는 영향이 제한적이었지만 미리 로드를 사용하면 브라우저가 자연스럽게 발견하기 전에 미리 로드하려는 중요한 리소스를 브라우저에 알릴 수 있습니다. 이는 스타일시트에 포함된 글꼴, 배경 이미지 또는 스크립트에서 로드된 리소스와 같이 찾기 어려운 리소스에 특히 유용합니다. 사전 연결은 교차 출처 서버에 대한 연결을 준비하는 데 도움이 되며 Time to First Byte와 같은 측정항목을 개선하는 데 도움이 될 수 있습니다. 출처는 알고 있지만 필요한 리소스의 정확한 URL은 모르는 경우에 유용합니다.

가져오기 우선순위는 이러한 리소스 힌트를 보완합니다. fetchpriority 속성을 통해 사용할 수 있는 마크업 기반 신호로, 개발자가 특정 리소스의 상대적 우선순위를 나타내는 데 사용할 수 있습니다. JavaScript와 Fetch API를 통해 priority 속성과 함께 이러한 힌트를 사용하여 데이터에 대해 실행되는 리소스 가져오기의 우선순위에 영향을 줄 수도 있습니다. 가져오기 우선순위는 미리 로드를 보완할 수도 있습니다. 최대 콘텐츠 렌더링 시간 이미지를 예로 들 수 있습니다. 이 이미지는 미리 로드되더라도 우선순위가 낮습니다. 다른 우선순위가 낮은 초기 리소스에 의해 이미지가 뒤로 밀리는 경우 가져오기 우선순위를 사용하면 이미지가 얼마나 빨리 로드되는지 확인할 수 있습니다.

리소스 우선순위

리소스 다운로드 시퀀스는 브라우저에서 페이지의 모든 리소스에 할당한 우선순위에 따라 다릅니다. 우선순위 계산 로직에 영향을 줄 수 있는 요소는 다음과 같습니다.

  • CSS, 글꼴, 스크립트, 이미지, 서드 파티 리소스와 같은 리소스 유형입니다.
  • 문서에서 리소스를 참조하는 위치 또는 순서입니다.
  • 스크립트에 async 또는 defer 속성이 사용되는지 여부입니다.

다음 표는 Chrome에서 대부분의 리소스에 우선순위를 지정하고 순서를 지정하는 방법을 보여줍니다.

  레이아웃 차단 단계에서 로드 레이아웃 차단 단계에서 한 번에 하나씩 로드
Blink
우선순위
VeryHigh 높음 중간 낮음 VeryLow
DevTools
우선순위
가장 높음 높음 중간 낮음 최저
기본 리소스
CSS (초기**) CSS (늦음**) CSS (미디어 불일치***)
스크립트 (조기** 또는 미리 로드 스캐너에서 가져온 것인지 여부) 스크립트 (늦음**) 스크립트 (비동기)
글꼴 글꼴 (rel=preload)
가져오기
이미지 (뷰포트 내) 이미지 (첫 5개 이미지: 10,000px2 초과) 이미지
미디어 (동영상/오디오)
프리페치
XSL
XHR (동기화) XHR/fetch* (비동기)

브라우저는 계산된 우선순위가 동일한 리소스를 발견된 순서대로 다운로드합니다. Chrome DevTools 네트워크 탭에서 페이지를 로드할 때 다양한 리소스에 할당된 우선순위를 확인할 수 있습니다. 테이블 헤더를 마우스 오른쪽 버튼으로 클릭하고 priority 열을 선택하여 포함해야 합니다.

Chrome DevTools의 Network 탭에 여러 글꼴 리소스가 나열되어 있습니다. 모두 &#39;최고&#39; 우선순위입니다.
BBC 뉴스 세부정보 페이지의 리소스 type = "font" 우선순위
Chrome DevTools의 Network 탭에 여러 글꼴 리소스가 나열되어 있습니다. 우선순위가 낮은 케이스와 높은 케이스가 혼합되어 있습니다.
BBC 뉴스 세부정보 페이지의 리소스 type = "script" 우선순위

우선순위가 변경되면 대규모 요청 행 설정 또는 도움말에서 초기 우선순위와 최종 우선순위를 모두 확인할 수 있습니다.

Chrome DevTools의 네트워크 탭 &#39;큰 요청 행&#39; 설정이 선택되어 있고 우선순위 열에는 우선순위가 높은 첫 번째 이미지와 아래에 다른 초기 우선순위인 중간이 표시되어 있습니다. 도움말에도 동일하게 표시됩니다.
DevTools의 우선순위 변경사항

가져오기 우선순위가 필요한 경우는 언제인가요?

이제 브라우저의 우선순위 지정 로직을 이해했으므로 페이지의 다운로드 순서를 조정하여 성능과 Core Web Vitals를 최적화할 수 있습니다. 다음은 리소스 다운로드의 우선순위에 영향을 미치도록 변경할 수 있는 몇 가지 예입니다.

  • <script><link>와 같은 리소스 태그를 브라우저에서 다운로드할 순서대로 배치합니다. 우선순위가 동일한 리소스는 일반적으로 발견된 순서대로 로드됩니다.
  • preload 리소스 힌트를 사용하여 필요한 리소스를 더 일찍 다운로드합니다. 특히 브라우저에서 초기에 쉽게 찾을 수 없는 리소스에 유용합니다.
  • async 또는 defer를 사용하여 다른 리소스를 차단하지 않고 스크립트를 다운로드합니다.
  • 브라우저가 더 중요한 상단 콘텐츠에 사용 가능한 대역폭을 사용할 수 있도록 아래쪽 콘텐츠를 지연 로드합니다.

이러한 기법은 브라우저의 우선순위 계산을 제어하여 성능과 Core Web Vitals를 개선하는 데 도움이 됩니다. 예를 들어 중요한 배경 이미지가 미리 로드되면 훨씬 더 일찍 발견되어 최대 콘텐츠 렌더링 시간 (LCP)이 개선됩니다.

이러한 핸들은 애플리케이션에 가장 적합한 리소스의 우선순위를 지정하기에는 충분하지 않을 수 있습니다. 가져오기 우선순위가 유용할 수 있는 시나리오는 다음과 같습니다.

  • 스크롤 없이 볼 수 있는 부분에 표시되는 이미지가 여러 개 있지만 모두 동일한 우선순위를 가질 필요는 없습니다. 예를 들어 이미지 캐러셀에서 처음 표시되는 이미지에만 우선순위가 높아야 하며, 나머지 이미지는 일반적으로 처음에는 화면 밖에 있으므로 우선순위가 낮게 설정될 수 있습니다.
  • 뷰포트 내의 이미지는 일반적으로 Low 우선순위로 시작합니다. 레이아웃이 완료되면 Chrome은 이러한 요소가 표시 영역에 있음을 감지하고 우선순위를 높입니다. 이렇게 하면 일반적으로 히어로 이미지와 같은 중요한 이미지를 로드하는 데 상당한 지연이 발생합니다. 마크업에서 가져오기 우선순위를 제공하면 이미지가 High 우선순위로 시작되고 훨씬 더 일찍 로드되기 시작합니다. 이를 어느 정도 자동화하기 위해 Chrome에서 처음 5개의 큰 이미지를 Medium 우선순위로 설정합니다. 이는 도움이 되지만 명시적 fetchpriority="high"가 더 좋습니다.

    CSS 배경으로 포함된 LCP 이미지를 조기에 검색하려면 여전히 미리 로드가 필요합니다. 배경 이미지의 우선순위를 높이려면 미리 로드에 fetchpriority='high'를 포함합니다.
  • 스크립트를 async 또는 defer로 선언하면 브라우저에 스크립트를 비동기식으로 로드하라는 신호를 보냅니다. 그러나 우선순위 표에 표시된 것처럼 이러한 스크립트에도 '낮음' 우선순위가 할당됩니다. 특히 사용자 환경에 중요한 스크립트의 경우 비동기 다운로드를 보장하면서 우선순위를 높일 수 있습니다.
  • JavaScript fetch() API를 사용하여 리소스 또는 데이터를 비동기식으로 가져오면 브라우저는 High 우선순위를 할당합니다. 특히 백그라운드 API 호출을 사용자 입력에 응답하는 API 호출과 혼합하는 경우 일부 가져오기를 더 낮은 우선순위로 실행하는 것이 좋습니다. 백그라운드 API 호출을 Low 우선순위로, 대화형 API 호출을 High 우선순위로 표시합니다.
  • 브라우저는 CSS 및 글꼴에 High 우선순위를 할당하지만 이러한 리소스 중 일부는 다른 리소스보다 중요할 수 있습니다. 가져오기 우선순위를 사용하여 중요하지 않은 리소스의 우선순위를 낮출 수 있습니다. 초기 CSS는 렌더링을 차단하므로 일반적으로 High 우선순위여야 합니다.

fetchpriority 속성

fetchpriority HTML 속성을 사용하여 link, img 또는 script 태그를 사용하여 다운로드할 때 CSS, 글꼴, 스크립트, 이미지와 같은 리소스 유형의 다운로드 우선순위를 지정합니다. 다음 값을 사용할 수 있습니다.

  • high: 리소스의 우선순위가 더 높으며 브라우저 자체 휴리스틱이 이를 방해하지 않는 한 브라우저에서 평소보다 더 높은 우선순위를 두도록 합니다.
  • low: 리소스의 우선순위가 낮으며 브라우저가 휴리스틱이 허용하는 경우 다시 우선순위를 낮추도록 합니다.
  • auto: 브라우저가 적절한 우선순위를 선택할 수 있는 기본값입니다.

다음은 마크업에서 fetchpriority 속성을 사용하는 예와 스크립트와 동일한 priority 속성의 예입니다.

<!-- We don't want a high priority for this above-the-fold image -->
<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 also 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>

브라우저 우선순위 및 fetchpriority의 효과

다음 표와 같이 fetchpriority 속성을 다양한 리소스에 적용하여 계산된 우선순위를 높이거나 낮출 수 있습니다. 각 행의 fetchpriority="auto" (◉)는 해당 유형의 리소스에 대한 기본 우선순위를 표시합니다. (Google 문서로도 제공됨)

  레이아웃 차단 단계에서 로드 레이아웃 차단 단계에서 한 번에 하나씩 로드
Blink
우선순위
VeryHigh 높음 중간 낮음 VeryLow
DevTools
우선순위
가장 높음 높음 중간 낮음 최저
기본 리소스
CSS (초기**) ⬆◉
CSS (늦음**)
CSS (미디어 불일치***) ⬆*** ◉⬇
스크립트 (조기** 또는 미리 로드 스캐너에서 가져온 것인지 여부) ⬆◉
스크립트 (늦음**)
스크립트 (async/defer) ◉⬇
글꼴
글꼴 (rel=preload) ⬆◉
가져오기
이미지 (뷰포트 내 - 레이아웃 후) ⬆◉
이미지 (첫 5개 이미지: 10,000px2 초과)
이미지 ◉⬇
미디어 (동영상/오디오)
XHR (동기화) - 지원 중단됨
XHR/fetch* (비동기) ⬆◉
프리페치
XSL

fetchpriority상대 우선순위를 설정합니다. 즉, 우선순위를 High 또는 Low로 명시적으로 설정하는 대신 기본 우선순위를 적절한 양만큼 올리거나 내립니다. 이로 인해 High 또는 Low 우선순위가 주어지는 경우가 많지만 항상 그런 것은 아닙니다. 예를 들어 fetchpriority="high"가 있는 중요 CSS는 '매우 높음'/'가장 높음' 우선순위를 유지하고 이러한 요소에 fetchpriority="low"를 사용하면 '높음' 우선순위가 유지됩니다. 이 두 경우 모두 우선순위를 High 또는 Low로 명시적으로 설정하지 않습니다.

사용 사례

브라우저에 리소스를 가져올 우선순위에 관한 추가 힌트를 제공하려면 fetchpriority 속성을 사용하세요.

LCP 이미지의 우선순위 높이기

fetchpriority="high"를 지정하여 LCP 또는 기타 중요한 이미지의 우선순위를 높일 수 있습니다.

<img src="lcp-image.jpg" fetchpriority="high">

다음 비교에서는 가져오기 우선순위 유무와 관계없이 LCP 배경 이미지가 로드된 Google 항공편 검색 페이지를 보여줍니다. 우선순위를 높음으로 설정하면 LCP가 2.6초에서 1.9초로 개선되었습니다.

Cloudflare 작업자를 사용하여 가져오기 우선순위를 사용하여 Google 항공편 페이지를 재작성하는 실험을 진행했습니다.

fetchpriority="low"를 사용하여 이미지 캐러셀의 오프스크린 이미지와 같이 당장 중요하지 않은 상단 이미지의 우선순위를 낮춥니다.

<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>

이미지 2~4는 뷰포트 외부에 있지만 high로 확대하고 load=lazy 속성이 추가되더라도 로드할 만큼 '충분히 가깝게' 있는 것으로 간주될 수 있습니다. 따라서 fetchpriority="low"이 올바른 해결책입니다.

이전에 Oodle 앱을 실험할 때 이 방법을 사용하여 로드 시 표시되지 않는 이미지의 우선순위를 낮췄습니다. 페이지 로드 시간이 2초 단축되었습니다.

Oodle 앱의 이미지 캐러셀에서 사용될 때 가져오기 우선순위의 나란히 비교 왼쪽의 브라우저는 캐러셀 이미지에 기본 우선순위를 설정하지만, 오른쪽의 예시보다 약 2초 더 느리게 이러한 이미지를 다운로드하고 페인트합니다. 오른쪽 예시에서는 첫 번째 캐러셀 이미지에만 더 높은 우선순위를 설정합니다.
첫 번째 캐러셀 이미지에만 높은 우선순위를 사용하면 페이지가 더 빠르게 로드됩니다.

미리 로드된 리소스의 우선순위 낮추기

미리 로드된 리소스가 다른 중요한 리소스와 경쟁하지 않도록 하려면 우선순위를 낮추면 됩니다. 이 기법은 이미지, 스크립트, CSS와 함께 사용합니다.

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

<!-- Preload CSS without blocking render, or other resources -->
<link rel="preload" as="style" href="theme.css" fetchpriority="low" onload="this.rel='stylesheet'">

스크립트 우선순위 변경

페이지가 상호작용이 가능하도록 하는 스크립트는 빠르게 로드되어야 하지만 더 중요한 렌더링 차단 리소스를 차단해서는 안 됩니다. 이러한 작업은 우선순위가 높은 async로 표시할 수 있습니다.

<script src="async_but_important.js" async fetchpriority="high"></script>

특정 DOM 상태를 사용하는 스크립트는 async로 표시할 수 없습니다. 하지만 페이지에서 나중에 실행되는 경우 우선순위를 낮춰 로드할 수 있습니다.

<script src="blocking_but_unimportant.js" fetchpriority="low"></script>

이렇게 하면 파서가 이 스크립트에 도달할 때 여전히 차단되지만 그 이전의 콘텐츠에는 우선순위가 부여됩니다.

완성된 DOM이 필요한 경우 defer 속성 (DOMContentLoaded 후에 순서대로 실행됨)을 사용하거나 페이지 하단의 async를 사용하는 것도 방법입니다.

중요하지 않은 데이터 가져오기의 우선순위 낮추기

브라우저는 높은 우선순위로 fetch를 실행합니다. 동시에 실행될 수 있는 가져오기가 여러 개인 경우 더 중요한 데이터 가져오기에 높은 기본 우선순위를 사용하고 덜 중요한 데이터의 우선순위를 낮출 수 있습니다.

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

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

가져오기 우선순위 구현 메모

가져오기 우선순위를 사용하면 특정 사용 사례에서 성능을 개선할 수 있지만 가져오기 우선순위를 사용할 때는 몇 가지 사항에 유의해야 합니다.

  • fetchpriority 속성은 지시어가 아닌 힌트입니다. 브라우저는 개발자의 환경설정을 따르려고 하지만 충돌을 해결하기 위해 리소스 우선순위에 대한 리소스 우선순위 환경설정을 적용할 수도 있습니다.
  • 가져오기 우선순위를 미리 로드와 혼동하지 마세요.

    • 미리 로드는 힌트가 아닌 필수 가져오기입니다.
    • 미리 로드하면 브라우저가 리소스를 일찍 발견할 수 있지만 여전히 기본 우선순위로 리소스를 가져옵니다. 반대로 가져오기 우선순위는 검색 가능성에는 도움이 되지 않지만 가져오기 우선순위를 높이거나 낮출 수는 있습니다.
    • 우선순위 변경의 효과보다 미리 로드의 효과를 관찰하고 측정하는 것이 더 쉬운 경우가 많습니다.

    가져오기 우선순위는 우선순위 지정 세부사항을 늘려 미리 로드를 보완할 수 있습니다. LCP 이미지의 <head>에서 첫 번째 항목 중 하나로 미리 로드를 이미 지정한 경우 high 가져오기 우선순위로 LCP가 크게 개선되지 않을 수 있습니다. 그러나 다른 리소스가 로드된 후에 미리 로드가 발생하는 경우 high 가져오기 우선순위로 LCP를 더 개선할 수 있습니다. 중요한 이미지가 CSS 배경 이미지인 경우 fetchpriority = "high"로 미리 로드합니다.

  • 우선순위에 따른 로드 시간 개선은 사용 가능한 네트워크 대역폭을 더 많은 리소스가 경쟁하는 환경에서 더 적합합니다. 이는 동시 다운로드가 불가능한 HTTP/1.x 연결이나 대역폭이 낮은 HTTP/2 또는 HTTP/3 연결에서 일반적입니다. 이러한 경우 우선순위를 지정하면 병목 현상을 해결하는 데 도움이 될 수 있습니다.

  • CDN은 HTTP/2 우선순위 지정을 일관되게 구현하지 않으며 HTTP/3도 마찬가지입니다. 브라우저가 가져오기 우선순위에서 우선순위를 전달하더라도 CDN에서 지정된 순서대로 리소스의 우선순위를 다시 지정하지 않을 수 있습니다. 따라서 가져오기 우선순위를 테스트하기가 어렵습니다. 우선순위는 브라우저 내부에서 그리고 우선순위를 지원하는 프로토콜 (HTTP/2 및 HTTP/3)과 함께 적용됩니다. 브라우저가 리소스를 요청할 때 우선순위가 자주 변경되므로 CDN 또는 출처 지원과 관계없이 내부 브라우저 우선순위에만 가져오기 우선순위를 사용하는 것이 좋습니다. 예를 들어 이미지와 같은 우선순위가 낮은 리소스는 브라우저가 중요한 <head> 항목을 처리하는 동안 요청되지 않는 경우가 많습니다.

  • 초기 설계에서 가져오기 우선순위를 권장사항으로 도입하지 못할 수도 있습니다. 개발 주기 후반에 페이지의 여러 리소스에 할당된 우선순위를 확인할 수 있으며, 기대에 미치지 않는 경우 가져오기 우선순위를 도입하여 추가로 최적화할 수 있습니다.

개발자는 의도된 목적(파서에서 감지하지 못한 리소스(서체, 가져오기, 배경 LCP 이미지) 미리 로드)에 맞게 미리 로드를 사용해야 합니다. preload 힌트의 위치는 리소스가 미리 로드되는 시점에 영향을 미칩니다.

가져오기 우선순위는 리소스를 가져올 때 리소스를 가져오는 방법에 관한 것입니다.

미리 로드 사용 관련 도움말

미리 로드를 사용할 때는 다음 사항에 유의하세요.

  • HTTP 헤더에 미리 로드를 포함하면 로드 순서에서 다른 모든 항목 앞에 미리 로드가 배치됩니다.
  • 일반적으로 미리 로드는 Medium 우선순위 이상인 항목의 경우 파서가 해당 항목에 도달하는 순서대로 로드됩니다. HTML 시작 부분에 미리 로드할 항목을 포함하는 경우 주의하세요.
  • 글꼴 미리 로드는 헤더 끝이나 본문 시작 부분에서 가장 효과적입니다.
  • 가져오기 미리 로드 (동적 import() 또는 modulepreload)는 가져오기가 필요한 스크립트 태그 뒤에 실행되어야 하므로 종속 항목이 로드되는 동안 평가될 수 있도록 스크립트가 먼저 로드되거나 파싱되어야 합니다.
  • 이미지 미리 로드는 기본적으로 Low 또는 Medium 우선순위가 적용됩니다. 비동기 스크립트 및 기타 낮은 우선순위 또는 최저 우선순위 태그를 기준으로 순서를 지정합니다.

기록

가져오기 우선순위는 2018년에 Chrome에서 오리진 트라이얼로 처음 실험되었으며 2021년에 importance 속성을 사용하여 다시 실험되었습니다. 당시에는 우선순위 힌트라고 불렀습니다. 이후 웹 표준 프로세스의 일환으로 인터페이스가 HTML의 경우 fetchpriority로, JavaScript의 Fetch API의 경우 priority로 변경되었습니다. 혼란을 줄이기 위해 이제 이 API를 가져오기 우선순위라고 합니다.

결론

개발자는 미리 로드 동작의 수정사항과 최근 Core Web Vitals 및 LCP에 대한 관심과 함께 가져오기 우선순위에 관심을 가질 수 있습니다. 이제 원하는 로드 시퀀스를 실행할 수 있는 추가 노브가 있습니다.