📀

대량 요소(element)로 인한 브라우저 렌더링 부하 해결

Tags
Performance
React
Date
2024/08/13
속성

개요

다이렉트 클라우드 서비스에서 대량의 파일을 (약 1000개 정도) 한번에 드래그 앤 드랍으로 업로드 시 에러가 발생하는 이슈가 발생했다.
업로드 하는 도중에 아래와 같은 화면이 떠버린 것이다.

원인이 뭘까

우선 이야기를 듣자마자 떠오른 것은 메모리 이슈였다. 현재 우리 서비스에서는 업로드 시 아래와 같이 업로드 할 파일들에 대한 상태창이 생긴다.
위 UI 를 만들기 위해서 당연히 browser 의 메모리에서는 파일들에 대한 데이터를 들고 있어야 했고, 이 때문에 메모리가 너무 많이 들어서 발생하는 문제라고 생각했다. 그런데 이상한 점이 있었다. drop box 에서 시험삼아 테스트를 했는데 이상 없이 1000개의 파일이 한번에 올라간 것이다!
같은 브라우저에서 한 서비스에서는 가능한 동작이 다른 서비스에서는 안돌아간다면, browser 의 메모리가 부족한 탓은 아닐 것이다. 그래서 다른 이유를 찾아보기 시작했다. 이내 찾아낸 원인은 바로 브라우저 랜더링 이슈였다.

해결

무한 스크롤

확인해보니 drop box 에서도 마찬가지로 업로드 시 각 파일의 상태를 표시하는 UI 가 존재했다. 다만 drop box 의 경우는 스크롤 내에서 보이는 영역만 렌더링 을 했다는 점이 큰 차이점이었다. 아래는 시험삼아 drop box 에 한번에 약 1000개의 파일을 업로드한 영상이다.
영상을 보면 알 수 있듯이 스크롤을 함에 따라서 업로드 상태 표시 UI 가 스크롤을 함에 따라서 새롭게 나타나고, 위의 아이템들은 없어지는 것을 볼 수 있다. 1000개의 상태를 UI 에 전부 표시한 것이 아니라 보이는 영역만 렌더링을 한 것이다.

react-window

직접 구현해서 해결할 수도 있겠으나 시간과 유지보수 측면에서 이미 잘 만들어지고 많이들 사용하는 라이브러리를 찾던 중 react-window 를 찾게 되었다. 리스트 영역이 가변적으로 변할 수 있었기 때문에 참고를 활용해서 react-virtualized-auto-sizer 와 함께 사용했다. 라이브러리 사용 자체도 어렵지 않아서 금방 문제를 해결할 수 있었다.
// Example import { FixedSizeList as List } from 'react-window'; const Row = ({ index, style }) => ( <div style={style}>Row {index}</div> // 바깥 스타일에 꼭 style 을 제대로 넣어줘야한다! ); const Example = () => ( <List height={150} itemCount={1000} itemSize={35} // 아이템의 height 값. 만약 가로 스크롤이라면 width 값일 것이다. 아이템의 size는 고정이어야한다 width={300} > {Row} </List> );
JavaScript
복사