INP 입력 지연: 원인, 진단 및 해결 방법

입력 지연으로 인해 발생하는 INP 문제를 찾고 개선하는 방법을 알아보세요.

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-03-04

입력 지연으로 인해 발생하는 Interaction to Next Paint (INP) 문제

이 페이지는 당사의 Interaction to Next Paint (INP) 시리즈 중 일부입니다. INP는 사용자 상호 작용부터 다음 시각적 업데이트까지의 총 시간을 측정합니다. 입력 지연은 INP를 구성하는 세 가지 단계 중 첫 번째 단계이며, 그 뒤를 이어 처리 시간(processing time)표시 지연(presentation delay)이 발생합니다. INP가 처음이라면 먼저 INP 문제를 식별하고 해결하는 방법에 대한 가이드를 읽어보세요.

INP TIP: 대부분의 경우 입력 지연은 웹페이지의 초기 로딩 단계에서 발생합니다. 이 시기는 브라우저가 스크립트를 파싱하고 실행하느라 가장 바쁜 때입니다.

입력 지연이란 무엇인가요?

입력 지연은 사용자가 웹 페이지와 상호 작용(예: 버튼 클릭 또는 키 누름)한 후 브라우저가 이벤트 콜백 처리를 시작하는 데 걸리는 시간을 의미합니다. 항상 약간의 입력 지연은 존재하지만(브라우저도 콜백을 예약할 시간이 필요함), 과도한 입력 지연은 브라우저가 예약된 다른 작업을 수행하느라 바빠서 상호 작용이 요청한 콜백을 즉시 예약할 수 없을 때 발생합니다.

입력 지연 시간 동안 사용자는 이미 작업(클릭, 탭 또는 키 누름)을 수행했지만 브라우저는 아직 관련 이벤트 핸들러 실행을 시작하지 않은 상태입니다. 사용자는 아무런 반응도 보지 못합니다. 이는 이벤트 핸들러가 활발하게 실행 중인 처리 시간이나 브라우저가 시각적 업데이트를 렌더링하는 표시 지연과는 다릅니다. 입력 지연은 메인 스레드의 혼잡으로 인해 발생하는 순수한 대기 시간입니다.

입력 지연과 INP

Interaction to Next Paint (INP)는 "입력 지연(Input Delay)", "처리 시간(Processing Time)" 및 "표시 지연(Presentation Delay)"의 3가지 하위 부분으로 나눌 수 있습니다.

입력 지연과 이전 Core Web Vitals인 "First Input Delay" (FID) 사이에 이름의 유사성이 있다는 것을 눈치채셨을 것입니다. Interaction to Next Paint는 2024년 3월에 FID를 대체하여 Core Web Vitals가 되었습니다. First Input Delay는 첫 번째 상호 작용과 이벤트 콜백 사이의 시간만을 측정했습니다. 비록 FID는 더 이상 사용되지 않지만, 입력 지연은 여전히 모든 Interaction to Next Paint 측정의 기초가 되기 때문에 중요합니다.

입력 지연의 중요성

많은 개발자들이 콜백 함수 최적화(처리 시간 최적화) 관점에서 INP 개선을 생각하기 때문에 입력 지연은 종종 간과됩니다. 물론 입력 지연이 INP에서 가장 큰 부분을 차지하는 것은 아니지만, 입력 지연을 최적화하면 종종 모든 INP 상호 작용을 한 번에 최적화하게 됩니다. 입력 지연을 줄이면 가장 나쁜 상호 작용만이 아니라 페이지의 모든 상호 작용이 개선됩니다.

CoreDash에서는 매시간 수백만 개의 Core Web Vitals 데이터 포인트를 수집합니다. 이 데이터에 따르면 입력 지연은 Interaction to Next Paint의 약 18%를 차지합니다. 이는 처리 시간이나 표시 지연보다는 적지만, 입력 지연의 근본 원인이 거의 항상 "잘못된 시점에 너무 많은 JavaScript가 실행됨"이기 때문에 종종 줄이기 가장 쉬운 단계입니다.

입력 지연의 원인

입력 지연은 메인 스레드가 다른 작업을 실행하느라 바쁠 때 발생합니다. 이러한 작업은 다음과 같은 원인에서 비롯될 수 있습니다.

  1. 초기 작업(Early tasks). 초기에 대기열에 추가된 일반, 지연(deferred) 및 비동기(async) 스크립트는 초기 작업을 생성합니다. 사용자가 페이지와 상호 작용할 가능성이 가장 높은 중요한 시작 기간 동안 실행되기 때문에 입력 지연의 가장 일반적인 원인입니다.
  2. 예약된 작업(Scheduled tasks). 일부 작업은 페이지 로드 시작 시 실행되지 않고 페이지가 로드된 후 예약될 수 있습니다. 이러한 작업 역시 INP를 방해하고 입력 지연을 일으킬 수 있습니다. 예를 들어, window.onload 이벤트 후에 실행되는 스크립트나 소위 최적화 플러그인에 의해 지연되는 스크립트가 있습니다. JavaScript에 대한 async와 defer 사용 시기에 대해 자세히 알아보세요.
  3. 반복 작업(Repeat tasks). 실행하는 데 비교적 오랜 시간이 걸리고 INP와 동시에 발생하는 setInterval()을 통한 반복 작업입니다.
  4. 중첩된 콜백(Overlapping callbacks). 중첩된 콜백은 입력 지연의 흔한 원인입니다. 여러 콜백이 서로 가깝게 예약되면 대기열이 생성되어 다음 상호 작용의 처리가 지연될 수 있습니다. 예를 들어, click 핸들러 직전에 발생하는 mouseover 핸들러는 마우스 오버 작업의 지속 시간만큼 클릭 처리를 뒤로 미룰 수 있습니다.

입력 지연 최소화

입력 지연을 최소화하려면 사용자가 페이지와 상호 작용하기 직전에 브라우저가 (긴) 작업을 수행하지 않도록 해야 합니다. 작업을 보다 적절한 시간으로 예약하거나, 작업이 오랫동안 실행되지 않도록 하거나, 작업이 실행되는 동안 상호 작용을 방지함으로써 이를 수행할 수 있습니다.
  1. 긴 초기 작업을 여러 개의 작은 작업으로 나눕니다. 긴 작업 중에는 브라우저가 사용자 입력에 응답할 수 없는 반면, 각 짧은 작업 후에는 브라우저가 사용자 입력에 응답할 수 있습니다. scheduler.yield()를 사용하거나 각 함수를 setTimeout(callback, 0)을 사용하여 0의 timeout으로 래핑하여 긴 작업을 나누세요.
  2. 대화형 요소 관리. 대화형 요소(예: 검색창)를 제어하는 JavaScript 코드가 완전히 로드되기 전에는 해당 요소를 표시하지 않는 것을 고려하세요. 이렇게 하면 클릭을 받을 준비가 되지 않은 요소에 대한 조기 클릭을 방지할 수 있습니다. 이 패턴의 UX를 최적화하려면 필요한 JavaScript의 로딩을 우선시하거나 기능이 활성화될 때까지 요소를 임시로 숨기거나 비활성화할 수 있습니다.
  3. 유휴 시간(Idle time) 스크립트 실행. requestIdleCallback()을 사용하여 중요하지 않은 스크립트가 브라우저의 유휴 기간 동안 실행되도록 예약하세요. 이 함수는 브라우저가 유휴 상태이고 사용자 입력을 처리할 필요가 없을 때 실행됩니다.
  4. 웹 워커(web workers)를 사용하여 브라우저의 메인 스레드 외부에서 JavaScript를 실행합니다. 웹 워커를 사용하면 스크립트가 메인 스레드 밖에서 실행될 수 있습니다. 이렇게 하면 메인 스레드가 차단되어 INP 입력 지연 문제가 발생하는 것을 방지할 수 있습니다.
  5. 반복 작업 중 보류 중인 입력이 있는지 확인합니다. 예약된 작업 세트를 실행하기 전에, 작업을 시작하기에 앞서 보류 중인 입력이 있는지 확인하세요. 보류 중인 입력이 있는 경우 메인 스레드에 먼저 yield하세요.
  6. 불필요한 코드 제거. 각 코드 줄이 잠재적으로 Interaction to Next Paint에 영향을 미치는 입력 지연을 일으킬 수 있으므로 스크립트를 정기적으로 감사하고 불필요한 코드나 전체 스크립트를 제거하세요. 실용적인 기술에 대해서는 JavaScript를 지연(defer)시키는 14가지 방법 가이드를 참조하세요.

scheduler.yield()로 작업 나누기

scheduler.yield() API는 긴 작업을 나누는 권장되는 방법입니다. 작업 대기열의 맨 뒤에 연속된 작업을 배치하는 setTimeout(callback, 0)과 달리, scheduler.yield()는 작업의 우선순위를 유지합니다. 즉, 브라우저가 보류 중인 사용자 입력을 처리한 후 가능한 한 빨리 코드를 재개함을 의미합니다. 재사용 가능한 도우미 함수는 다음과 같습니다.

async function yieldToMain() {
  if ('scheduler' in window && 'yield' in window.scheduler) {
    return await window.scheduler.yield();
  }
  // Fallback for browsers without scheduler.yield()
  return new Promise((resolve) => {
    setTimeout(resolve, 0);
  });
}

// Example: break up a long initialization sequence
async function initializeApp() {
  loadCriticalFeatures();
  await yieldToMain();  // Let the browser handle any pending input

  loadSecondaryFeatures();
  await yieldToMain();

  loadAnalytics();
  await yieldToMain();

  loadNonEssentialWidgets();
}

scheduler.yield()가 내부적으로 어떻게 작동하는지에 대한 자세한 내용은 Chrome Developers 블로그를 참조하세요.

scheduler.postTask()로 작업 우선순위 지정하기

scheduler.yield()가 작업을 나누는 반면, scheduler.postTask()는 작업 우선순위에 대한 세밀한 제어 기능을 제공합니다. 이 API는 세 가지 우선순위 수준을 허용합니다. 가장 높은 우선순위가 필요한 중요한 작업을 위한 "user-blocking", 중간 우선순위 작업을 위한 "user-visible", 유휴 시간 동안 실행되어야 하는 가장 낮은 우선순위 작업을 위한 "background"입니다.

postTask()를 사용하면 필수적이지 않은 작업이 사용자 상호 작용을 차단하지 않도록 할 수 있습니다. 다음은 UI 업데이트를 가장 높은 우선순위로 유지하면서 백그라운드 우선순위로 분석 작업을 예약하는 실용적인 예입니다.

// High priority: UI feedback runs first
scheduler.postTask(() => {
  showLoadingSpinner();
}, { priority: 'user-blocking' });

// Medium priority: fetch data
scheduler.postTask(async () => {
  const data = await fetchSearchResults(query);
  renderResults(data);
}, { priority: 'user-visible' });

// Low priority: analytics can wait
scheduler.postTask(() => {
  trackSearchEvent(query);
  sendToAnalytics('search', { query });
}, { priority: 'background' });

프로덕션 환경에서 사용하기 전에 scheduler.postTask()에 대한 브라우저 지원 표를 확인하세요. 해당 API를 지원하지 않는 브라우저의 경우, 백그라운드 작업에는 requestIdleCallback()을, 우선순위가 높은 작업에는 queueMicrotask()를 fallback으로 사용하세요.

실질적인 시사점

이것이 귀하의 사이트에 어떤 의미가 있을까요? 다음은 WordPress 및 React/Next.js에 대한 구체적인 권장 사항입니다.

WordPress

WordPress는 플러그인 기반 아키텍처로 인해 종종 테마와 다수의 플러그인을 함께 제공합니다. 플러그인과 테마 모두 기능 측면에서 JavaScript에 의존하는 경우가 많습니다. 이러한 플러그인과 테마는 서드파티 개발자가 유지 관리하기 때문에 사용자가 그 콘텐츠를 통제할 수 없습니다. 즉, 파일을 변경하여 "나쁜 코드"를 최적화할 수 없습니다. 스크립트가 지금 당장 정상적으로 작동하더라도 다음 업데이트 후에도 그럴 것이라는 보장은 없습니다.

WordPress에서 입력 지연을 최소화하고 Interaction to Next Paint (INP)를 최적화하려면 다음 단계를 따르세요.

  • 가능한 한 플러그인 사용을 피하세요. 플러그인은 기능을 쉽게 추가할 수 있는 방법이지만, 종종 페이지에 스크립트를 추가합니다. 이러한 스크립트는 INP에 영향을 미치는 입력 지연을 일으킬 것입니다. 각 플러그인에 대해 커스텀 코드나 서버 측 솔루션으로 동일한 기능을 구현할 수 있는지 자문해 보세요.
  • 가벼운 테마를 선택하세요. 많은 WordPress 테마가 "모든 것을 제공"합니다. 아주 좋은 아이디어처럼 보일 수 있지만, 이는 사용하지 않으면서도 귀중한 CPU 시간을 차지하는 기능들로 가득 차 있을 가능성이 높다는 것을 의미합니다.
  • 페이지 빌더를 피하세요. Elementor나 WPBakery와 같은 페이지 빌더는 레이아웃 구성을 위한 사용자 친화적인 시각적 인터페이스를 제공합니다. 안타깝게도 방문자에게 레이아웃을 표시하기 위해 무거운 스크립트에 의존하는 경우가 많습니다.
  • 필요할 때만 스크립트를 로드하세요. WordPress는 모든 페이지에서 모든 스크립트를 로드하는 경향이 있습니다. 이 문제를 해결하려면 자식(child) 테마를 만들고 페이지 유형별로 불필요한 스크립트의 등록을 취소하세요.
function my_deregister_scripts() {
  if ( ! is_page( 'contact' ) ) {
    // Deregister contact form script on non-contact pages
    wp_dequeue_script( 'contact-form-script' );
  }
}
add_action( 'wp_enqueue_scripts', 'my_deregister_scripts' );
  • Tag Manager 감사. Google Tag Manager 컨테이너에는 시간이 지남에 따라 종종 태그가 축적됩니다. 페이지 로드 중에 실행되는 각 태그는 메인 스레드에 작업을 추가합니다. 사용하지 않는 태그를 제거하고, 적절한 트리거를 설정하고(예: 전환 페이지에서만 마케팅 태그 실행), Tag Manager의 내장 타이밍 보고서를 사용하여 느린 태그를 식별하세요.
  • 필수적이지 않은 서드파티 스크립트 지연. 채팅 위젯, 피드백 도구 및 소셜 미디어 임베드는 즉시 로드될 필요가 없습니다. requestIdleCallback()이나 스크롤 기반 트리거를 사용하여 사용자가 필요로 할 가능성이 있을 때만 로드하세요. 자세한 전략은 JavaScript를 지연(defer)시키는 14가지 방법에 대한 가이드를 읽어보세요.

React / Next.js

React 및 Next.js 사이트는 주로 JavaScript로 구동됩니다. 시작 스크립트를 실행하고, 컴포넌트를 하이드레이션(hydrating)하고, 가상 DOM을 처리하는 데 모두 시간이 걸리며 이로 인해 Interaction to Next Paint (INP)에 입력 지연이 발생할 수 있습니다. 다행스러운 점은 React와 Next.js 모두 이를 효과적으로 관리할 수 있는 도구를 제공한다는 것입니다.

  • 서버 컴포넌트(Next.js App Router의 React Server Components)를 사용하세요. 서버 컴포넌트는 서버에서 렌더링되며 클라이언트에 JavaScript를 전혀 보내지 않으므로 메인 스레드 시간을 놓고 경쟁하는 코드의 양을 직접적으로 줄여줍니다.
  • 올바른 전략으로 서드파티 스크립트를 로드하세요. Next.js에서는 하이드레이션 후에 필요한 스크립트에 strategy="afterInteractive"를 설정한 next/script 컴포넌트를 사용하거나, 브라우저 유휴 시간 동안 로드될 수 있는 스크립트에 strategy="lazyOnload"를 사용하세요. 기본 원리에 대해서는 async vs defer JavaScript 가이드를 참조하세요.
  • idle-until-urgent 패턴을 구현하세요. 이 패턴은 컴포넌트가 실제로 필요할 때 활성화되는 동기식 fallback을 유지하는 한편, 중요하지 않은 초기화에 requestIdleCallback()을 사용하여 백그라운드 작업보다 사용자 상호 작용의 우선순위를 높입니다.
  • 컴포넌트 지연 로딩(Lazy load). 즉시 필요하지 않은 컴포넌트는 클라이언트 전용 컴포넌트용 { ssr: false }와 함께 React.lazy() 또는 Next.js dynamic()을 사용하여 지연 로딩하세요.
  • 대화형 컴포넌트에 Suspense를 사용하세요. 무거운 컴포넌트가 백그라운드에서 로드되는 동안 페이지의 나머지 부분이 렌더링되고 대화형이 될 수 있도록 <Suspense> 경계로 대화형 컴포넌트를 래핑하세요. 이렇게 하면 하나의 느린 컴포넌트가 전체 페이지의 입력 처리를 차단하는 것을 방지할 수 있습니다.
  • 긴급하지 않은 업데이트에 React transitions를 사용하세요. 중요하지 않은 상태 업데이트를 startTransition()으로 래핑하여 사용자가 새로운 상호 작용을 수행할 경우 React가 이를 중단할 수 있도록 하세요. 이렇게 하면 대규모 리렌더링이 진행 중인 경우에도 UI 응답성을 유지할 수 있습니다.

다른 INP 단계 탐색하기

INP를 제어하려면 다른 두 단계도 함께 해결하세요.

  • 처리 시간(Processing Time): 상호 작용 중에 실행되는 이벤트 핸들러 코드를 최적화하세요. 대부분의 페이지에서 최적화 노력의 상당 부분이 여기서 성과를 거둡니다.
  • 표시 지연(Presentation Delay): 이벤트 처리 후 이어지는 렌더링 및 페인팅 작업을 줄이세요. DOM이 큰 복잡한 페이지에서 이것은 종종 가장 큰 단계입니다.

전체적인 진단 워크플로는 INP 문제를 찾고 해결하는 방법에 대한 가이드를 참조하고, 전체 개요를 보려면 INP 허브 페이지로 돌아가세요.

CoreDash는 제가 직접 쓰려고 만들었습니다.

1KB 미만, EU 호스팅, 쿠키 동의 배너 없음. 이제 MCP까지 지원합니다.

CoreDash 무료 체험
INP 입력 지연: 원인, 진단 및 해결 방법Core Web Vitals INP 입력 지연: 원인, 진단 및 해결 방법