왜 Interaction to Next Paint가 개발자들의 반응성에 대한 생각을 바꾸었는가

발행: (2026년 4월 3일 PM 12:10 GMT+9)
17 분 소요
원문: Dev.to

Source: Dev.to

위의 링크에 포함된 전체 텍스트를 제공해 주시면, 해당 내용을 한국어로 번역해 드리겠습니다. 현재는 번역할 본문이 없으므로, 번역이 필요한 텍스트를 복사해서 알려 주세요.

Introduction

수년간 First Input Delay (FID) 가 Core Web Vitals 의 응답성 지표였습니다. 이는 사용자의 첫 번째 상호작용과 브라우저가 이를 처리하기 시작하는 시점 사이의 지연을 측정했습니다. 대부분의 사이트는 첫 번째 클릭에만 입력 지연을 캡처하고 그 이후는 무시했기 때문에 FID 를 쉽게 통과했습니다. 예를 들어 드롭다운 메뉴를 열 때 페이지가 2초 동안 멈추어도 FID 는 이를 기록하지 않았습니다.

2024년 3월, Google 은 FID 를 Interaction to Next Paint (INP) 로 교체했습니다. 이 변화는 겉모습만 바뀐 것이 아니라, INP 가 전체 페이지 방문 동안 모든 상호작용 을 측정하고, 각 상호작용의 입력 지연, 처리, 페인트 전 과정을 추적함으로써 “응답성” 의 의미를 근본적으로 바꾸었습니다.

이 글에서는 왜 이러한 변화가 중요한지, INP 가 실제로 무엇을 측정하는지, 그리고 규칙이 바뀐 지금 응답성을 어떻게 생각해야 하는지를 설명합니다.

Why FID fell short

  • Only the first interaction was measured. If your page loaded cleanly but became sluggish after JavaScript hydration, after a state update triggered a heavy re‑render, or after a third‑party script loaded, FID would still report a good score. Users experiencing a slow, janky interface would not be reflected in the metric.
  • Only input delay was counted. FID ignored how long the event handler itself took to run and how long the browser took to update the screen after the handler finished. A click with zero input delay but 800 ms of processing and paint would score perfectly under FID.
  • Over‑optimistic pass rate – Chrome’s analysis of real‑user data showed that > 90 % of websites passed the 100 ms FID threshold, making it essentially useless as a differentiator, while users still reported feeling that sites were slow and unresponsive.

Photo by cottonbro studio on Pexels

Interaction to Next Paint (INP)

INP는 상호작용의 전체 수명 주기를 세 단계로 캡처합니다:

단계설명
Input delay사용자의 동작(클릭, 탭, 키 입력)과 브라우저가 이벤트 핸들러 실행을 시작하는 사이의 시간. 이는 FID가 측정하던 것이지만, INP는 첫 번째 상호작용이 아니라 모든 상호작용에 대해 측정합니다.
Processing time이벤트 핸들러가 실행되는 데 걸리는 시간. 예를 들어 버튼을 클릭했을 때 상태 업데이트가 발생해 React가 큰 컴포넌트 트리를 다시 렌더링한다면, 그 전체 렌더링 시간은 처리 시간에 포함됩니다.
Presentation delay핸들러가 끝난 시점과 브라우저가 화면에 픽셀을 업데이트하는 사이의 시간. 여기에는 레이아웃 계산, 페인팅, 컴포지팅이 포함됩니다. width, height, position과 같이 레이아웃을 트리거하는 CSS 속성을 변경하면 이 지연이 크게 늘어날 수 있습니다.

페이지 방문에 대한 INP 값은 일반적으로 가장 높은 지연을 보이는 상호작용(많은 상호작용이 있는 경우 통계적 보정을 적용)입니다.

Google의 기준

INP 점수의미
≤ 200 ms좋음
200 – 500 ms개선 필요
> 500 ms불량

web.dev INP 문서에서는 통계적 방법론을 설명하고 있습니다. 대부분의 사이트에서 보고되는 INP 값은 98번째 백분위수 상호작용이며, 이는 일반 사용자가 방문 중 겪을 수 있는 최악의 경험을 나타냅니다.

“빠른 로드”에서 “빠른 사용”으로

FID 기준

  • 반응성은 주로 초기 페이지 로드 중에 긴 작업을 피하는 것이었습니다.
  • 첫 번째 클릭 전에 JavaScript가 메인 스레드를 차단하지 않으면 통과되었습니다.
  • 최적화는 코드 스플리팅, 레이지 로딩, 비핵심 스크립트 지연 등에 초점을 맞추었으며, 본질적으로 “빠른 로드” 전술이었습니다.

INP 기준

  • 반응성은 전체 세션 동안 유지되어야 합니다.
  • 초점이 “빠른 사용”으로 이동합니다.

FID는 통과했지만 INP에서는 실패하는 패턴

  1. 상호작용 시 무거운 상태 업데이트 – 필터를 클릭해 500개의 리스트 항목을 다시 렌더링하면 메인 스레드가 차단됩니다. FID에서는 첫 번째 상호작용이 아니면 보이지 않았지만, INP에서는 매번 카운트됩니다.
  2. 이벤트 핸들러 내 동기식 레이아웃 계산 – 클릭 핸들러 안에서 레이아웃 속성(offsetHeight, getBoundingClientRect())을 읽으면 강제 레이아웃이 발생해 메인 스레드가 차단됩니다. 자세한 내용은 Google의 forced layout 문서를 참고하세요.
  3. 상호작용 시 실행되는 서드파티 스크립트 – 클릭마다 실행되는 분석 스크립트, 첫 상호작용 시 초기화되는 채팅 위젯, 터치를 가로채는 동의 관리 플랫폼 등이 모두 INP에 영향을 줍니다.

“INP는 ‘페이지가 얼마나 빨리 로드되는가’에서 ‘사용자가 하는 모든 행동에 얼마나 빨리 반응하는가’로 대화를 바꾸었습니다. 이는 훨씬 더 높은 장벽이며, 바로 사용자가 실제로 신경 쓰는 부분입니다.” – Dennis Traina, 137Foundry

Source:

실용적인 INP 최적화

1. 긴 이벤트 핸들러 분할

클릭 핸들러가 50 ms 이상 걸리는 작업을 트리거한다면, 작업을 나눕니다. scheduler.yield()(Chrome에서 사용 가능하고 다른 브라우저에서는 플래그 뒤에 있음) 또는 setTimeout(0)을 사용해 작업 조각 사이에 브라우저에 제어권을 반환합니다. 이렇게 하면 브라우저가 작업 조각 사이에 대기 중인 사용자 입력과 페인팅 업데이트를 처리할 수 있습니다.

async function handleFilterClick(selectedFilter) {
  // UI를 즉시 업데이트
  showLoadingIndicator();

  // 브라우저가 로딩 상태를 그리도록 양보
  await scheduler.yield();

  // 이제 비용이 많이 드는 필터링 수행
  const filtered = applyFilter(data, selectedFilter);

  // 결과를 렌더링하기 전에 다시 양보
  await scheduler.yield();

  renderResults(filtered);
}

2. 빠른 상호작용 디바운스

스크롤 핸들러, 리사이즈 리스너, 입력 중 검색 같은 경우 초당 수십 개의 이벤트가 발생할 수 있습니다. 사용자가 상호작용을 멈춘 뒤 한 번만 비용이 많이 드는 작업이 실행되도록 디바운스하세요.

function debounce(fn, wait) {
  let timeout;
  return (...args) => {
    clearTimeout(timeout);
    timeout = setTimeout(() => fn.apply(this, args), wait);
  };
}

// 예시: 검색 입력 디바운스
const handleSearch = debounce((query) => {
  fetchResults(query).then(renderResults);
}, 300);

3. 계산을 Web Worker로 이동

DOM에 직접 접근할 필요가 없는 데이터 처리, 정렬, 기타 CPU 집약적인 작업은 Web Worker에 오프로드합니다. 이렇게 하면 메인 스레드가 사용자 인터랙션과 페인팅에 전념할 수 있습니다.

// main.js
const worker = new Worker('worker.js');
worker.postMessage({ type: 'sort', payload: largeArray });

worker.onmessage = (event) => {
  const sorted = event.data;
  renderSortedList(sorted);
};
// worker.js
self.onmessage = (event) => {
  if (event.data.type === 'sort') {
    const sorted = event.data.payload.sort((a, b) => a - b);
    self.postMessage(sorted);
  }
};

4. 강제 동기 레이아웃 감소

  • 같은 작업(task) 안에서 DOM을 변경한 뒤 레이아웃 속성(offsetHeight, clientWidth 등)을 읽는 것을 피합니다.
  • DOM 읽기와 쓰기를 별도로 배치하거나 requestAnimationFrame 패턴을 사용합니다.
// 나쁨: 쓰기 후 읽기 (강제 레이아웃)
button.addEventListener('click', () => {
  button.style.width = '200px';
  const height = button.offsetHeight; // 강제 레이아웃
  console.log(height);
});

// 좋음: 읽기/쓰기 분리
button.addEventListener('click', () => {
  requestAnimationFrame(() => {
    button.style.width = '200px';
  });
  requestAnimationFrame(() => {
    const height = button.offsetHeight;
    console.log(height);
  });
});

5. 서드파티 스크립트 감사

  • 분석, 채팅 위젯, 동의 관리 스크립트를 필요 시에 로드합니다(예: 사용자 상호작용 이후).
  • async/defer 속성이나 동적 import()를 사용해 인터랙션 중에 메인 스레드를 차단하지 않도록 합니다.

INP 측정 및 모니터링

  1. Chrome DevToolsPerformance 패널을 열고 사용자 흐름을 기록한 뒤 Interaction to Next Paint 섹션을 찾습니다.
  2. Web Vitals JavaScript 라이브러리 – 사이트에 web-vitals를 추가하여 실시간으로 INP를 캡처합니다:
import { getINP } from 'web-vitals';

getINP((metric) => {
  console.log('INP:', metric.value);
  // Send to your analytics endpoint
});
  1. Search Console – Google Search Console이 이제 Core Web Vitals 보고서에서 INP를 보고하며, 좋은 / 개선 필요 / 낮은 페이지의 분포를 보여줍니다.

결론

INP는 FID를 대체하여 전체 사용자 여정 전반에 걸친 응답성에 대한 전체적인 시각을 제공합니다. 모든 상호작용의 입력 지연, 처리 시간, 그리고 표시 지연을 측정함으로써 이전에 눈에 띄지 않았던 성능 문제를 드러냅니다.

좋은 소식은 동일한 성능‑엔지니어링 원칙—짧은 작업, 비동기 작업, 강제 레이아웃 방지, 그리고 신중한 서드파티 관리—이 여전히 적용된다는 것입니다. 이제는 페이지 라이프사이클 전반에 걸쳐 지속적으로 적용해야 합니다.

가장 오래 실행되는 상호작용을 감사하는 것부터 시작하고, 무거운 핸들러를 분할하며, Web Worker와 디바운싱을 활용하십시오. 이러한 패턴을 적용하면 INP 지표에서 사이트를 “개선 필요”에서 “양호”로 끌어올릴 수 있으며—무엇보다 실제 사용자에게 더 부드럽고 응답성이 높은 경험을 제공하게 됩니다.

웹 워커

대형 배열과 JSON 페이로드 파싱은 메인 스레드에서 수행될 필요가 없습니다. Web Worker는 사용자 인터랙션을 차단할 수 없는 백그라운드 스레드에서 JavaScript를 실행합니다.

React 재렌더 최적화

  • React.memo – 함수형 컴포넌트의 불필요한 재렌더를 방지합니다.
  • useMemo – 의존성이 변경될 때만 실행되도록 비용이 많이 드는 계산을 메모이제이션합니다.
  • useTransition – 비긴급 상태 업데이트를 낮은 우선순위로 표시하여, 무거운 업데이트 중에도 UI가 반응하도록 유지합니다.

Transitions에 대한 React 문서에서는 startTransition이 무거운 업데이트 중 UI를 어떻게 반응 가능하게 유지하는지 설명합니다.

Core Web Vitals 개요

세 가지 Core Web Vitals 전체와 진단 워크플로우(현장 데이터부터 수정까지)를 더 폭넓게 살펴보려면 Core Web Vitals 완전 가이드를 확인하세요. 이 가이드는 LCP, CLS, 그리고 INP를 다룹니다.

Photo by Daniil Komov on Pexels
Daniil Komov이 Pexels에 올린 사진

Real‑User Monitoring (RUM)

Lab tools like Lighthouse simulate interactions, but they cannot replicate the variety of real user behavior. Some users click rapidly, some use keyboard navigation, and some interact with elements that your test script never touches.

Real‑user monitoring is the only reliable way to track INP.

web‑vitals 라이브러리를 활용한 INP 모니터링

  • web‑vitals 라이브러리는 실제 방문자들의 INP 값을 보고합니다.
  • 분석 파이프라인에 통합하여 어느 페이지와 어떤 상호작용이 가장 높은 INP 값을 갖는지 확인하세요.
  • 어트리뷰션 빌드는 최악의 상호작용을 일으킨 정확한 요소와 이벤트 유형을 식별합니다.

137Foundry 팀은 일반적으로 web‑vitals 모니터링을 Chrome DevTools → Interactions 트랙과 결합하여 현장 데이터에서 식별된 특정 느린 상호작용을 진단합니다. 실사용자 감지와 실험실 조사의 이 조합이 INP 문제를 해결하는 가장 빠른 경로입니다.

INP 표준

INP는 반응형 웹 애플리케이션이 무엇인지에 대한 기준을 높였습니다.

  • FID는 단일 순간만을 측정하므로 비교적 쉽게 통과할 수 있었습니다.
  • INP방문 전체에 걸쳐 모든 페이지의 모든 상호작용이 200 ms 이내에 응답하도록 요구합니다.

이 높은 기준은 사용자 경험을 보다 정직하게 반영합니다. INP 최적화에 투자한 사이트는 실제로 사용이 더 빠르며, 이는 다음과 같은 효과로 이어집니다.

  • 더 나은 참여도
  • 낮은 이탈률
  • 경쟁이 치열한 검색 결과에서의 순위 우위
0 조회
Back to Blog

관련 글

더 보기 »