🚀 프론트엔드 성능 최적화 가이드: 성능 최적화란 무엇인가?
주니어 개발자 시절, 저는 기능 구현에만 몰두했던 것 같습니다.
버튼을 만들고, API를 연결하며 화면을 동작하게 만드는 것만으로도 하루가 금세 지나갔죠. ⏱️
새로운 기술이 나올 때마다 "저게 SEO에 좋다더라", "SSR이라 렌더링 속도가 빠르더라" 같은 얕은 정보만 접하며,
필요에 의해서 배우기보다는 "다들 배우니까", "신기술이니까 배워야지"라는 생각으로 학습했습니다. 💡
그때는 생각하지 못했습니다.
“사용자가 실제로 느끼는 성능”이 얼마나 중요한지 말이죠. ⚡
하지만 서비스가 커지고 사용자 수가 늘어나면서, 점점 깨닫게 되었습니다.
사용자가 체감하는 속도가 곧 서비스 만족도와 비즈니스 성과를 좌우한다는 사실을요. 🚀
실제 사용자들의 피드백을 보면 명확하게 드러납니다.
“페이지가 너무 느려요.”
“버튼을 눌러도 반응이 늦어요.”
“기능에는 문제가 없는데, 사용자가 페이지를 떠나는 이유는 무엇일까?”
바로 랜더링 시간과 페이지 로딩 속도입니다.
즉, 기능에는 문제가 없더라도, 속도가 느리다는 이유만으로 고객은 이탈한다는 것이죠.
구글과 다양한 연구에서도 이를 강조합니다.
성능이 저하되면 사용자가 떠나고, 매출이 감소한다.
성능이 향상되면 사용자가 늘고, 매출이 오른다.
실제 수치로 보면 사용자 체감은 더욱 극명하게 드러납니다.
| 1초 → 3초 | 32% 증가 |
| 1초 → 5초 | 90% 증가 |
| 1초 → 6초 | 106% 증가 |
| 1초 → 10초 | 123% 증가 |
즉, “기능이 정상적으로 동작한다”는 것만으로는 충분하지 않습니다.
페이지가 빠르게 표시되고, 사용자 입력에 즉시 반응해야 비로소 서비스 만족도가 올라가고, 비즈니스 성과도 개선됩니다.
이 글에서는 프론트엔드 성능 최적화가 왜 필수인지, 그리고 실제로 어떤 방법과 도구를 사용해 최적화를 진행할 수 있는지 단계별로 정리해보겠습니다.
🚀 프론트엔드 성능 최적화, 어디서부터 시작할까?
어디서 시작해야할지 길을 잃어서, 프론트엔드 성능 최적화에 대해 감을 잡고자 토스에서 공개한 영상을 시청했습니다.
영상에서 핵심적으로 다룬 내용을 정리하면 다음과 같습니다.
1️⃣ 성능 최적화, 무조건 하면 안 된다!
- 성능 최적화는 필요할 때만 하는 것이 좋습니다.
- 단계별로 생각해보세요:
- “하면 좋을 것 같은데?” → 아직 하지 말자
- “해야 될 것 같아” → 한 번 더 고민
- “이제 진짜 해야겠다!” → 프로파일링부터 시작
💡 실제 사용자 환경에서 문제가 발생하는지를 먼저 확인하는 것이 중요합니다.
개발자는 보통 더 좋은 환경에서 테스트하기 때문에, 평범한 상황에서는 성능 문제가 눈에 잘 안 보입니다.
2️⃣ 최악의 환경에서 테스트하라
- 성능 문제는 평균값이 아닌 최악의 환경에서 발생합니다.
- p50(중간값)보다는 p95, p99 같은 극단적인 상황에서 테스트해야 합니다.
- 가장 안 좋은 상황에서 문제가 생기면, 사용자는 서비스에 낙인을 찍게 됩니다.
3️⃣ 최적화의 두 가지 측면
3-1️⃣ 초기 로딩 속도 ⏱
- 대역폭: 자바스크립트 번들이 크면 클수록 로딩 속도가 느려집니다.
- 공통 번들 관리: 여러 페이지에서 공통으로 쓰는 코드는 하나의 번들로 묶어 관리.
- ⚠️ 주의: 번들을 너무 쪼개면 화면이 어색하게 깜빡일 수 있음
예시: 토스에서 리액트 네이티브를 도입한 이유
→ 네트워크가 아닌 기기에서 로딩을 처리하기 위해
3-2️⃣ 런타임 반응성 ⚡
- 초당 프레임(FPS) 기준으로 얼마나 부드럽게 렌더링 되는지가 중요
- 불필요한 상태 변화를 줄이는 것이 핵심
🔹 상태 최적화 예시 (useMemo)
import { useMemo, useState } from 'react';
function ExpensiveCalculation({ number }) {
const [count, setCount] = useState(0);
// number가 바뀔 때만 계산 수행
const factorial = useMemo(() => {
console.log('계산 중...');
const calc = (n) => (n <= 1 ? 1 : n * calc(n - 1));
return calc(number);
}, [number]);
return (
<div>
<p>Factorial of {number}: {factorial}</p>
<button onClick={() => setCount(count + 1)}>Click me {count}</button>
</div>
);
}
- useMemo를 사용하면, 연산이 오래 걸리는 값도 필요할 때만 재계산
🔹 컴포넌트 메모화 (React.memo)
import React, { memo } from 'react';
const Item = memo(({ value }) => {
console.log('렌더링 Item:', value);
return <div>{value}</div>;
});
export default function ItemList({ items }) {
return (
<div>
{items.map((item) => (
<Item key={item.id} value={item.value} />
))}
</div>
);
}
- 한 화면에 많은 컴포넌트가 있을 때 React.memo를 사용하면 불필요한 재렌더링 방지
4️⃣ 핵심 정리 📝
- 성능 최적화는 무조건 하지 말고, 필요할 때만
- 최악의 환경에서 테스트 → p95, p99 기준
- 초기 로딩 속도 최적화:
- 번들 크기 최소화
- 공통 번들 관리
- 런타임 성능:
- 불필요한 상태 변화 줄이기
- 연산 비용 큰 값은 useMemo
- 반복되는 컴포넌트는 React.memo
영상 링크: 토스 프론트엔드 성능 최적화 🎥
🔹 성능 최적화란?
성능 최적화는 사용자가 서비스를 더 빠르고 쾌적하게 이용할 수 있도록, 불필요한 자원 낭비를 줄이고 응답 속도를 개선하는 작업입니다.
중요한 포인트: 단순히 "코드를 줄이는 것"에 그치지 않습니다.
성능 최적화는 프론트엔드 전체 생태계와 맞닿아 있습니다.
- 코드 레벨 → 불필요한 리렌더링 방지, 최소한의 state 관리
- 네트워크 레벨 → 번들 크기 최소화, 이미지/폰트 최적화
- 브라우저 레벨 → 효율적인 DOM 조작, Reflow/Repaint 비용 최소화
- 운영 레벨 → 실제 사용자 환경에서 성능 모니터링 및 개선
즉, 기획 → 개발 → 빌드 → 배포 → 운영까지 전 과정에서 고려해야 하는 큰 주제입니다.
🔹 왜 성능 최적화가 중요한가?
- 사용자 경험(UX) 개선
- 페이지 클릭 시 빠른 반응 → 만족도 상승
- 로딩 3초 이상 → 이탈률 급격히 증가
- 비즈니스 지표와 직결
- 아마존: 로딩 속도 0.1초 느려질 때 매출 1% 감소
- 네이버, 카카오 등 대형 서비스도 성능 전담 조직 운영
- 검색 엔진 최적화(SEO)
- 구글 Core Web Vitals(LCP, FID, CLS) 반영 → 성능 좋은 페이지일수록 검색 노출 유리
- 접근성과 보편성 확보
- 느린 네트워크 환경에서도 원활한 서비스 제공
- 리소스 과다 → 저속 환경 사용자 이용 불가
🔹 성능 최적화 사례
- 이미지 최적화 → WebP/AVIF 포맷, 필요 없는 해상도 줄이기
- 코드 스플리팅(Code Splitting) → React.lazy, dynamic import 활용
- 렌더링 최적화 → React.memo, useMemo, useCallback
- 캐싱 전략 → CDN 배포, Cache-Control 헤더 설정
작은 개선이 쌓이면 사용자 체감 성능이 크게 달라집니다.
🔹 렌더링 최적화
// React.memo 예제
const Child = React.memo(({ name }) => {
console.log("렌더링:", name);
return <div>{name}</div>;
});
// useCallback & useMemo 예제
function Parent({ items }) {
const [count, setCount] = React.useState(0);
const increment = React.useCallback(() => setCount(c => c + 1), []);
const filteredItems = React.useMemo(() =>
items.filter(item => item.active), [items]
);
return (
<div>
<button onClick={increment}>Count: {count}</button>
{filteredItems.map(item => <Child key={item.id} name={item.name} />)}
</div>
);
}
- Virtualization → 긴 리스트 최적화: react-window, react-virtualized
- 조건부 렌더링 → 필요할 때만 mount
- Suspense + lazy → 지연 로딩
🔹 코드 관리 / 상태 관리 최적화
- Context 최소화 → 불필요한 리렌더링 방지
- 비동기 최적화 → 캐싱, 요청 중복 방지 (SWR, React Query)
// 상태 최소화 & 파생 데이터 useMemo
function TodoList({ todos }) {
const completedCount = React.useMemo(
() => todos.filter(todo => todo.done).length,
[todos]
);
return <div>완료된 항목: {completedCount}</div>;
}
// React Query 예제
import { useQuery } from 'react-query';
function Todos() {
const { data, isLoading } = useQuery('todos', fetchTodos);
if (isLoading) return <div>Loading...</div>;
return data.map(todo => <div key={todo.id}>{todo.title}</div>);
}
🔹 빌드 / 배포 최적화
// dynamic import & React.lazy
const LazyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
<React.Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</React.Suspense>
);
}
- 이미지 압축, WebP/AVIF 활용, Next.js next/image
- Tree Shaking → 불필요한 라이브러리 제거
- CDN 배포 + 서비스워커(PWA) 고려
🔹 디버깅 / 측정 도구
| React DevTools Profiler | 컴포넌트 렌더링 시간/횟수 확인 |
| Lighthouse | 성능 + 접근성 + SEO + PWA 종합 점검 |
| why-did-you-render | 불필요한 리렌더링 탐지 |
| Web Vitals | LCP, FID, CLS, INP 등 사용자 경험 지표 |
| Chrome DevTools Performance | JS 실행 시간, 메모리, Reflow/Repaint 원인 분석 |
🔹 공통 지표 정리
- Core Web Vitals → 구글 표준 지표(LCP, FID, CLS, INP)
- Web Vitals → 사용자 경험 중심
- Lighthouse → 성능 + 접근성 + SEO + PWA
- React Profiler → 리액트 렌더링 성능
- Chrome DevTools Performance → 브라우저 저수준 성능 분석
요약:
LCP/FID/CLS = 표준 지표
SEO/PWA = Lighthouse 전용
렌더링 성능 = React Profiler 전용
이 글은 프론트엔드 성능 최적화 시리즈 1편으로, 다음 글에서는 React에서 렌더링 최적화 방법을 더 깊게 다룰 예정입니다. 🚀
💬 공부하며 정리한 글이라 부족한 부분이 있을 수 있습니다.
잘못된 내용이나 추가로 설명이 필요하다고 생각되는 부분이 있다면, 댓글로 알려주시면 감사하겠습니다! 🙏
'개발 로그 > 오늘의 개발읽기' 카테고리의 다른 글
| [개발읽기 vol.6] 오픈소스 기여 방법 완벽 가이드 | 주니어·시니어 개발자가 얻는 이점 (0) | 2025.09.09 |
|---|---|
| [개발읽기 vol.5] 2025년 리액트 상태관리 가이드: Redux, Recoil, Zustand, Jotai, MobX 비교 (2) | 2025.09.08 |
| [개발읽기 vol.4] Next.js 면접 대비: "왜 Next.js를 사용했나요?" 답변 예시 & 가이드 (1) | 2025.09.02 |
| [개발읽기 vol.2] 개발자 필수 스킬, AI 코딩 활용 가이드 (1) | 2025.09.01 |
| [개발읽기 vol.1] 개발자 회사 생활 필수 용어 모음 (2) | 2025.09.01 |