- Published on
프론트엔드 개발에서의 Virtualized Rendering 이해하기
- Authors
- Name
- Deokgoo Kim
소개
프론트엔드 개발자로서 대규모 리스트나 인피니티 스크롤을 구현하다 보면 메모리 부족 현상을 겪게 됩니다. 메모리가 부족하면 브라우저는 메모리를 초기화하여 리로드를 유발하는 경우도 있습니다. 특히 요즘의 리스트 아이템은 단순하지 않습니다. 여러 이벤트와 유저 행동 트래킹, 다양한 기능들이 포함되어 있어 메모리 사용량이 더욱 증가합니다. 이를 해결하기 위해 사용하는 방법 중 하나가 바로 virtualized rendering입니다. virtual component, virtual scroll 등의 용어로도 불리지만, 정확한 표현은 virtualized rendering입니다. 이를 이해하기 위해 원리를 알아보겠습니다.
Virtualized Rendering의 원리
Virtualized rendering은 사용자가 실제로 보지 않는 DOM 요소를 렌더링하지 않음으로써 메모리 사용량을 줄이는 기술입니다. 이는 특히 대규모 리스트를 처리할 때 유용합니다. 스크롤 위치에 따라 필요한 요소만을 동적으로 렌더링하고, 보이지 않는 요소는 제거하여 성능을 최적화합니다.
Virtualized Rendering의 구현 방법
virtualized rendering을 구현하는 방법은 여러 가지가 있습니다. 여기서는 Vanilla JS를 사용하여 다양한 방법으로 virtualized rendering을 구현하는 방법을 설명하겠습니다.
1. Intersection Observer를 사용한 Virtualized Rendering
Intersection Observer API를 사용하면 요소가 뷰포트 내에 들어오거나 나갈 때를 감지할 수 있습니다. 이를 활용하여 보이는 영역의 요소만 렌더링하고, 나머지 요소는 제거할 수 있습니다.
예제 코드
<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Intersection Observer Virtualized Rendering</title>
<style>
#container {
height: 500px;
overflow-y: auto;
border: 1px solid #ccc;
}
.item {
height: 35px;
border-bottom: 1px solid #eee;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
const container = document.getElementById('container');
const itemHeight = 35;
const totalItems = 1000;
const items = [];
function createItem(index) {
const item = document.createElement('div');
item.className = 'item';
item.textContent = 'Item ' + index;
return item;
}
function renderItems(start, end) {
container.innerHTML = '';
for (let i = start; i < end; i++) {
const item = createItem(i);
container.appendChild(item);
items.push(item);
}
}
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const item = entry.target;
const index = items.indexOf(item);
renderItems(index - 10, index + 10);
}
});
},
{
root: container,
rootMargin: '0px',
threshold: 0.1,
}
);
renderItems(0, 20);
items.forEach((item) => observer.observe(item));
</script>
</body>
</html>
2. 패딩을 활용한 Virtualized Rendering
패딩을 활용하면 스크롤 위치에 따라 실제로 렌더링되는 요소를 이동시키면서 빈 공간을 패딩으로 채워 넣을 수 있습니다.
예제 코드
<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Padding Virtualized Rendering</title>
<style>
#container {
height: 500px;
overflow-y: auto;
border: 1px solid #ccc;
position: relative;
}
.padding {
height: 0;
}
.item {
height: 35px;
border-bottom: 1px solid #eee;
position: absolute;
width: 100%;
}
</style>
</head>
<body>
<div id="container">
<div id="items"></div>
</div>
<script>
const container = document.getElementById('container');
const itemsContainer = document.getElementById('items');
const itemHeight = 35;
const totalItems = 1000;
const visibleItems = Math.ceil(container.clientHeight / itemHeight);
let startIndex = 0;
function renderItems() {
itemsContainer.innerHTML = '';
const endIndex = startIndex + visibleItems;
for (let i = startIndex; i < endIndex; i++) {
const item = document.createElement('div');
item.className = 'item';
item.style.top = `${i * itemHeight}px`;
item.textContent = 'Item ' + i;
itemsContainer.appendChild(item);
}
container.style.paddingTop = `${startIndex * itemHeight}px`;
container.style.paddingBottom = `${(totalItems - endIndex) * itemHeight}px`;
}
function onScroll() {
const scrollTop = container.scrollTop;
startIndex = Math.floor(scrollTop / itemHeight);
renderItems();
}
container.addEventListener('scroll', onScroll);
// 초기 렌더링
renderItems();
</script>
</body>
</html>
성능 최적화의 중요성
virtualized rendering은 대규모 데이터를 처리할 때 성능을 최적화하는 데 매우 중요합니다. 메모리 사용량을 줄이고, 브라우저의 리소스 낭비를 방지하여 사용자 경험을 향상시킬 수 있습니다. 특히 모바일 환경에서는 메모리 자원이 제한적이기 때문에 virtualized rendering의 효과가 더욱 큽니다.
결론
대규모 리스트와 인피니티 스크롤은 현대 웹 애플리케이션에서 자주 사용되는 기능입니다. 그러나 메모리 부족 문제를 해결하지 않으면 성능 저하와 같은 문제가 발생할 수 있습니다. virtualized rendering은 이러한 문제를 해결하기 위한 효과적인 방법으로, 성능 최적화와 사용자 경험 향상에 큰 도움이 됩니다. 프로젝트에 적용해 보기를 권장합니다.