| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
- 생산성
- 프롬프트 엔지니어링
- #IT트렌드
- github
- 가상시나리오
- GTM
- YouTrack
- 보안
- Gemini
- swagger
- 벡터 인덱싱
- ASP.NET
- GA4
- jQuery 4.0
- ChatGPT
- Dooray
- Github Copilot
- 미래
- 리포지토리 인텔리전스
- Passkey
- The Singularity is Here
- AI
- Visual Studio 2026
- 패스키
- GPT
- SEO
- geo
- 프론트엔드
- jira
- Today
- Total
Beyond Frontend
INP 최적화 실용 가이드 본문

1. INP란 무엇이며, 왜 중요한가?
INP는 단순히 새로운 성능 지표가 아니라, 사용자가 웹사이트와 상호작용할 때 느끼는 '체감 반응성'을 가장 정확하게 측정하는 핵심 기준입니다. 사용자가 버튼을 클릭했는데 화면이 멈칫하거나 느리게 반응하는 경험은 직접적인 이탈과 매출 하락으로 이어지기 때문에, INP 개선은 비즈니스 성과와 직결되는 중요한 과제입니다.
1.1. FID를 대체한 새로운 반응성 지표, INP
INP와 이전 지표인 FID(First Input Delay)의 차이를 식당에 비유해 쉽게 이해할 수 있습니다.
- FID (과거): 손님이 식당에 들어와 처음으로 웨이터를 불렀을 때, 웨이터가 주문을 받으러 오기까지 걸린 대기 시간입니다. 주문을 처리하고 음식이 나오는 시간은 측정하지 않습니다.
- INP (현재): 손님이 식당에 머무는 동안 모든 주문과 요청에 대해, 웨이터를 부른 순간부터 음식이 실제로 식탁에 나올 때까지 걸린 전체 시간 중 가장 오래 걸렸던 경험을 평가합니다.
| 구분 | FID (구 지표) | INP (신규 표준) |
| 측정 대상 | 최초 1회 상호작용만 측정 | 페이지 내 모든 상호작용 측정 |
| 측정 범위 | 입력 지연(Delay) 시간만 측정 | 전체 소요(Total) 시간 측정 |
| 목적 | 사용자의 첫인상 평가 | 사용자의 전체 경험 평가 |
| 상태 | Deprecated (2024년 3월 폐지) | Active (핵심 성능 지표) |
예를 들어, "장바구니 담기" 버튼을 눌렀을 때를 생각해 봅시다. FID는 브라우저가 클릭을 인지하고 작업을 '시작'하는 데 0.01초가 걸렸다면 "빠르다"고 판단합니다. 하지만 실제 사용자는 복잡한 로직 처리 때문에 3초 뒤에 "담겼습니다" 팝업을 보게 된다면 "느리다"고 느낍니다. FID는 이 3초를 측정하지 못하는 '반쪽짜리' 지표였습니다.
반면, INP는 사용자가 최종 결과를 눈으로 확인하는 3초까지의 전체 시간을 측정하므로, 사용자가 느끼는 실제 체감 속도를 훨씬 더 정확하게 반영합니다.
1.2. INP의 세 가지 구성 요소
INP는 아래 세 가지 시간의 합으로 계산됩니다. 최적화는 이 세 구간을 각각 줄여나가는 과정입니다.
INP = 입력 지연 (Input Delay) + 처리 시간 (Processing Time) + 프레젠타이션 지연 (Presentation Delay)
- 입력 지연 (Input Delay): 사용자가 클릭한 순간부터, 브라우저가 다른 무거운 작업을 처리하느라 이벤트 핸들러(예: click 함수)를 실행하기 시작할 때까지의 대기 시간입니다.
- 처리 시간 (Processing Time): 이벤트 핸들러 내부의 JavaScript 코드가 실행되어 완료되기까지 걸리는 시간입니다. 복잡한 DOM 탐색이나 계산이 이 구간을 늘립니다.
- 프레젠테이션 지연 (Presentation Delay): JavaScript 실행이 끝난 후, 브라우저가 변경된 내용을 화면에 실제로 그려주기(Paint)까지 걸리는 시간입니다. DOM 구조가 복잡할수록 이 시간이 길어집니다.
2. jQuery 환경을 위한 INP 핵심 최적화 전략
지금부터 소개할 전략들은 jQuery 및 레거시 환경의 특성을 고려하여 즉시 적용 가능한 실용적인 코드 패턴입니다. 각 전략이 INP의 세 가지 구성 요소 중 어떤 부분을 집중적으로 개선하는지에 초점을 맞춰 살펴보겠습니다.
2.1. 즉각적인 피드백으로 체감 속도 높이기
사용자가 액션을 취했을 때, 서버 통신과 같은 무거운 작업을 기다리지 않고 UI를 먼저 업데이트하여 즉각적인 시각적 피드백을 제공하는 것은 INP 개선의 핵심입니다.
AS-IS (기존 방식): 서버 응답을 기다리는 UI
function addToCart() {
// 1. 서버에 통신 (느림)
$.ajax({
// ... ajax options ...
success: function() {
// 2. 통신이 모두 완료된 후에야 얼럿 표시 (늦게 반응)
alert("상품을 카트에 담았습니다.");
}
});
}
TO-BE (개선 방식): 즉시 반응하는 UI
function addToCart() {
// 1. 즉시 UI 업데이트 (버튼 비활성화 및 텍스트 변경)
$('#btnCart').addClass('loading').text('담는 중...');
// 2. 무거운 작업(서버 통신)은 다음 프레임으로 양보
setTimeout(function() {
$.ajax({
success: function() {
// 3. 통신 완료 후 최종 UI 업데이트
alert("담겼습니다.");
$('#btnCart').removeClass('loading');
}
});
}, 0);
}
이 패턴은 무거운 로직을 setTimeout(..., 0)으로 분리하여 브라우저가 UI 업데이트를 먼저 처리하게 만듭니다. 이를 통해 사용자가 인지하는 처리 시간(Processing Time)을 획기적으로 단축시켜 "즉시 반응한다"는 느낌을 줍니다.
2.2. 이벤트 핸들러 과부하 방지
디바운싱 (Debouncing): 검색창의 keyup 이벤트처럼 짧은 시간에 수십 번씩 발생하는 이벤트는 매번 처리할 필요가 없습니다. 디바운싱은 사용자의 입력이 끝난 후 일정 시간이 지나면 딱 한 번만 함수를 실행시키는 기법입니다.
Before: 타이핑할 때마다 함수 실행
$('#searchInput').on('keyup', function() {
heavyProcess(); // 자음/모음 입력 때마다 실행되어 버벅임 유발
});
After: 입력이 멈추고 0.3초 뒤 한 번만 실행
var timer;
$('#searchInput').on('keyup', function() {
if (timer) clearTimeout(timer);
timer = setTimeout(function() {
heavyProcess();
}, 300);
});
이 기법은 불필요한 함수 호출을 막아 처리 시간을 극적으로 줄여줍니다.
이벤트 위임 (Event Delegation): 상품 목록의 각 아이템에 개별적으로 click 이벤트를 바인딩하면 수백 개의 이벤트 리스너가 메모리를 차지하고 초기화 속도를 저하시킵니다. 상위 컨테이너에 이벤트를 한 번만 바인딩하고, 어떤 자식 요소에서 이벤트가 발생했는지 확인하는 것이 훨씬 효율적입니다.
변경 전: 각 요소에 인라인 핸들러 할당
<div id="reviewList">
<button class="btn_review" onclick="showReview(1)">리뷰 보기 1</button>
<button class="btn_review" onclick="showReview(2)">리뷰 보기 2</button>
<!-- ... 수백 개의 버튼 ... -->
</div>
변경 후: 상위 요소에 이벤트 위임
<!-- HTML에서는 onclick 속성을 제거하고 식별자만 남깁니다. -->
<div id="reviewList">
<button class="btn_review" data-review-id="1">리뷰 보기 1</button>
<button class="btn_review" data-review-id="2">리뷰 보기 2</button>
</div>
// 상위 요소(#reviewList)에 이벤트를 한 번만 바인딩합니다.
$('#reviewList').on('click', '.btn_review', function() {
// 클릭된 버튼의 data-review-id 값을 가져와서 로직을 수행합니다.
var reviewId = $(this).data('review-id');
showReview(reviewId);
});
2.3. 렌더링 병목 현상 제거
레이아웃 스래싱 (Layout Thrashing) 방지: 반복문 안에서 DOM의 높이를 읽고(Read) 바로 그 값을 변경하는(Write) 코드는 프론트엔드 성능 최적화에서 가장 먼저 피해야 할 안티패턴(Anti-pattern)입니다. 브라우저가 매번 강제로 레이아웃을 다시 계산하게 만들어 화면을 그대로 멈춰버리는 주범입니다.
Before: 읽고 쓰기를 반복 (매우 느림)
$('.item').each(function() {
var h = $(this).height(); // 읽기 (Read)
$(this).css('height', h + 10 + 'px'); // 쓰기 (Write) -> 즉시 재계산 강제
});
After: 읽기와 쓰기를 분리 (빠름)
var heights = [];
// 1. 읽기 작업만 먼저 일괄 수행
$('.item').each(function() {
heights.push($(this).height());
});
// 2. 쓰기 작업 일괄 수행
$('.item').each(function(i) {
$(this).css('height', heights[i] + 10 + 'px');
});
이 패턴은 브라우저 렌더링 과정을 최적화하여 프레젠테이션 지연을 최소화합니다.
jQuery 애니메이션을 CSS Transition으로 대체: jQuery의 .slideDown(), .fadeIn() 같은 메서드는 JavaScript를 이용해 메인 스레드에서 픽셀을 직접 계산하므로 애니메이션 도중 다른 사용자 입력을 막습니다. 대신 GPU 가속을 사용하는 CSS transform과 opacity 속성을 활용하고, JavaScript는 클래스를 추가/제거하는 역할만 해야 합니다.
Before: jQuery 애니메이션 (메인 스레드 점유)
$('#menu').slideDown(300);
After: CSS 클래스 토글 (GPU 가속 활용)
/* CSS */
.menu {
transform: scaleY(0);
transform-origin: top; /* 위에서 아래로 펼쳐지도록 기준점 설정 */
transition: transform 0.3s ease;
}
.menu.active {
transform: scaleY(1);
}
/* JavaScript */
$('#menu').addClass('active');
content-visibility를 이용한 렌더링 지연: 상품 상세 설명이나 리뷰 목록처럼 스크롤이 긴 영역에 이 CSS 속성을 적용하면, 브라우저는 현재 화면 밖에 있는 방대한 DOM 요소의 렌더링 계산을 건너뜁니다. 사용자가 스크롤하여 해당 영역에 가까워지면 그때 렌더링을 시작합니다.
.goods_detail_area, .review_list_area {
content-visibility: auto;
contain-intrinsic-size: 1000px; /* 대략적인 높이값 */
}
⚠️ 중요: content-visibility: auto;를 사용할 때는 contain-intrinsic-size 속성을 함께 사용하는 것이 좋습니다. 이 속성은 브라우저에게 해당 요소가 렌더링될 때 차지할 대략적인 높이(예: 1000px)를 알려주어, 스크롤 시 화면이 울컥거리는 레이아웃 쉬프트(Layout Shift) 현상을 방지합니다.
이 속성 하나만으로도 페이지 초기 로딩 및 탭 전환 시 발생하는 프레젠테이션 지연을 크게 줄일 수 있습니다.
2.4. 효율적인 스크립트 작성
DOM 접근 캐싱 (Selector Caching): jQuery 선택자 $(...)는 실행될 때마다 DOM 전체를 탐색하는 비용이 큰 작업입니다. 이벤트 핸들러나 반복문 안에서 동일한 요소를 여러 번 찾아야 한다면, 변수에 한 번 저장해두고 재사용하는 것이 필수입니다.
Before: 클릭 때마다 DOM 탐색
$('.btn_add').on('click', function() {
$('.cart_count').text( parseInt($('.cart_count').text()) + 1 );
});
After: 변수에 저장해두고 재사용
var $cartCount = $('.cart_count');
$('.btn_add').on('click', function() {
$cartCount.text( parseInt($cartCount.text()) + 1 );
});
이 간단한 습관이 처리 시간을 눈에 띄게 단축시킵니다.
Long Task 쪼개기: 50ms 이상 연속으로 실행되는 JavaScript 작업은 'Long Task'로 간주되며, 이 시간 동안 브라우저는 사용자의 클릭이나 키보드 입력에 전혀 반응하지 못합니다. 긴 작업을 setTimeout으로 여러 조각으로 나누어 실행하면, 각 조각 사이에 브라우저가 사용자 입력을 처리할 틈을 줄 수 있습니다. 이것이 '양보(Yielding)' 기법이며, 입력 지연을 줄이는 핵심 원리입니다.
// Before: 120ms 동안 메인 스레드를 차단하는 Long Task
function processAllData() {
processDataChunk1(); // 50ms 소요
processDataChunk2(); // 40ms 소요
processDataChunk3(); // 30ms 소요
}
// After: 작업을 분리하여 브라우저에 제어권 양보 (Yielding)
function processAllDataYielding() {
setTimeout(processDataChunk1, 0); // 각 작업을 별도의 태스크로 분리
setTimeout(processDataChunk2, 0);
setTimeout(processDataChunk3, 0);
}
3. 개선 효과 측정 및 검증 방법
코드 개선은 반드시 데이터 기반의 검증을 동반해야 합니다. 다행히 라이브 배포 없이도 로컬 환경에서 충분히 효과를 측정하고 증명할 수 있는 강력한 도구들이 있습니다.
3.1. 로컬 환경에서 INP 문제 디버깅하기
Chrome 개발자 도구 Performance 패널: 개발자가 INP 문제를 분석하는 가장 강력하고 필수적인 도구입니다.
- F12 키를 눌러 개발자 도구를 열고 Performance 탭으로 이동합니다.
- 녹화 버튼(⚫️)을 누른 후, 테스트하려는 페이지 상호작용(예: 버튼 클릭, 메뉴 열기)을 수행합니다.
- 녹화 중지 버튼을 누릅니다.
- 타임라인의 Interactions 트랙에서 빨간색 삼각형이 표시된 긴 막대(Long Task)를 찾습니다. 이것이 INP를 유발하는 범인입니다.
- 해당 막대를 클릭하면 Summary 탭에서 Input Delay, Processing Time, Presentation Delay 중 어느 구간이 병목인지 정확한 시간과 함께 확인할 수 있습니다.
CPU 스로틀링: 개발자 PC의 성능은 일반 사용자 환경보다 훨씬 좋기 때문에 문제를 인지하기 어렵습니다. Performance 탭의 설정(⚙️)에서 CPU 옵션을 4x slowdown으로 설정하면, 보급형 모바일 기기 환경을 시뮬레이션하여 숨어있던 병목 구간을 명확하게 찾아낼 수 있습니다.
3.2. 배포 없이 개선 효과 검증하기
로컬 오버라이드 (Local Overrides): 이 기능은 "운영 사이트의 특정 JS/CSS 파일만 내 로컬 파일로 바꿔치기해서 테스트하는 치트키"입니다. 서버 배포 없이 실제 운영 환경에서 내 코드가 어떻게 동작하는지 테스트할 수 있습니다.
- 설정: F12 > Sources 탭 > Overrides 메뉴 선택 > Select folder for overrides를 클릭하여 로컬 폴더를 지정합니다.
- 파일 선택: Page 탭에서 수정할 파일(예: main.js)을 우클릭하고 Save for overrides를 선택합니다.
- 수정 및 테스트: 이제 개발자 도구에서 직접 코드를 수정하고 저장(Ctrl+S)하면, 페이지를 새로고침해도 수정된 코드가 적용된 상태로 사이트가 실행됩니다. 이 상태에서 Performance 패널로 개선 효과를 측정하면 됩니다.
Lighthouse와 TBT 지표: INP는 실제 사용자 데이터가 필요하지만, 개발 단계에서는 **TBT(Total Blocking Time)**라는 대용 지표를 사용합니다. **"TBT가 개선되면 INP도 반드시 개선된다"**고 봐도 무방합니다. 코드 수정 전후에 개발자 도구의 Lighthouse 탭을 실행하여 TBT 점수가 얼마나 줄었는지 비교하면, 배포 후의 INP 개선 효과를 확실하게 예측할 수 있습니다.
3.3. 주요 측정 도구 모음
INP 측정 및 분석에 사용되는 도구들을 목적에 따라 정리하면 다음과 같습니다.
- 실 사용자 데이터 측정 (현황 파악):
- PageSpeed Insights: URL을 입력하여 지난 28일간의 실제 사용자 INP 점수를 확인합니다.
- Google Search Console: 사이트 전체에서 INP 문제가 있는 URL 그룹을 식별합니다.
- 실시간 디버깅 및 원인 분석:
- Web Vitals 확장 프로그램: 크롬에 설치하여 현재 보고 있는 페이지의 INP를 실시간으로 확인합니다.
- Chrome 개발자 도구: 문제의 원인이 되는 코드를 찾아내고 수정 효과를 검증하는 가장 중요한 도구입니다.
4. 결론: 지금 바로 시작할 수 있는 Action Item
INP 개선은 지속적인 과정이지만, 적은 노력으로 큰 효과를 볼 수 있는 '가성비' 높은 작업들이 분명히 존재합니다. 우리 개발팀이 즉시 실행에 옮길 수 있는 우선순위 높은 Action Item은 다음과 같습니다.
- 최우선 과제 (사용자 체감 개선): '장바구니 담기' 등 핵심 전환 기능에 setTimeout을 활용한 '즉각적인 피드백(낙관적 UI)' 패턴을 적용하여 서버 응답 대기 시간을 없앱니다.
- 가성비 높은 리팩토링: slideDown, fadeIn 등 모든 jQuery 애니메이션을 CSS 클래스 토글 방식으로 전환하여 메인 스레드 부하를 줄입니다.
- 반복 상호작용 최적화: 검색창 키 입력, 스크롤 등 빈번한 이벤트에 디바운싱 로직을 적용하여 불필요한 스크립트 실행을 방지합니다.
- 대규모 DOM 최적화: 상품 상세 설명, 리뷰 목록 등 스크롤이 긴 영역에 content-visibility: auto CSS 속성을 추가하여 초기 렌더링 비용을 절감합니다.
이 문서를 닫기 전에, 지금 바로 개발자 도구의 Performance 탭을 열어 여러분 서비스의 'Long Task'를 하나 찾아내십시오. 이 가이드의 기법 중 하나를 적용하여 그 빨간 막대가 사라지는 것을 직접 확인하는 것이 INP 개선의 가장 확실한 첫걸음입니다.
'Frontend Essentials' 카테고리의 다른 글
| .NET Framework만 사용하던 당신을 위한 .NET Core 생존 가이드: 가장 충격적인 변화 4가지 (0) | 2026.01.02 |
|---|---|
| 모바일 상품상세 INP 최적화 (0) | 2025.12.28 |
| 프론트엔드 체감 속도 최적화 전략 (0) | 2025.12.21 |
| 웹 접근성, 그거 왜 해야 돼요? 개발자라면 꼭 알아야 할 A11y 가이드! (0) | 2025.12.21 |
| GEO 최적화를 위한 상품 페이지 JSON-LD 개선 (0) | 2025.12.17 |
