Lazy Loading과 기타 이야기
우리는 흔히 웹 페이지의 성능을 향상시키고자 할 때 3R을 얘기합니다.
1. Request 개수 줄이기
2. Resource 사이즈 줄이기
3. Rendering 시간 단축
Webpack을 통한 모듈 번들링, 이번에 얘기해 볼 Lazy Loading이 1번,
Webpack-Minify, Obfuscation, Tree-Shaking, Code-Splitting, 이미지 최적화가 2번,
CRP 최적화, Reflow의 최소화, 부드러운 애니메이션 등이 3번 예시에 속한다고 볼 수 있습니다.
이번 포스트에서는 1번 예시 중 Lazy Loading과 기타 내용에 관해 이야기를 해볼까 합니다.
이미지와 같이 사이즈가 큰 데이터를 로딩할 때, 사용자의 브라우저 화면에 나타나지 않은 이미지까지 로딩을 하면 페이지의 로딩이 느려질 수 있습니다.
이런 상황에서 유용하게 쓰일 수 있는 것이 바로 Lazy Loading이며, 예시 그림과 같이 사용자 브라우저에 보이는 이미지만 로딩을 하고 다른 이미지들은 사용자가 스크롤 하면서 이미지에 가까워지면 로딩을 합니다.
전체 이미지를 한 번에 로딩하지 않고, 사용자가 필요한 부분만 보여줄 수 있기 때문에 로딩에 대한 비용을 줄일 수 있다는 장점이 있습니다.
꼭 이미지만 해당 하는 것이 아닌, 웹에서 특정 위치나 컴포넌트에 도달하였을 때 API를 호출하는 것, 데이터베이스에서 기본적으로 PK가 되는 값만 전달해주고, 추가 요청이 생길 경우에만 DB에서 상세 내용을 불러오는 것 등 모두 Lazy Loading의 예시라고 할 수 있습니다.
정리를 해보자면, Lazy Loading은 웹 페이지의 성능을 향상시키기는 하지만 정확히 Request의 개수(총량)를 줄이는 것은 아니며, 그냥 간단히 브라우저의 초기 렌더링 최적화를 위한 작업이라고 생각하시면 좋을 것 같습니다.
그럼 좀 더 나아가서, 우리가 Request의 개수를 줄여야 하는 이유는 무엇일까요?
바로, 네트워크 통신 비용으로 인한 렌더링 블록(Rendering Blocking) 문제를 방지하기 위함입니다.
브라우저 마다 특정 개수의 호스트를 가지고 있고, 그 호스트를 가지고 서버에 리소스를 요청합니다.
그리고, 각 요청이 끝나면 다시 호스트는 서버와 새롭게 커넥션하여 통신합니다.
이는 Chrome Devtools의 Network Debugger를 통해서도 쉽게 확인할 수 있는데, 아래 사진과 같이 데이터를 내려 받는 속도보다 서버와 커넥션, SSL 적용 등의 작업이 훨씬 오래걸린다는 사실을 알 수 있습니다.
* 실제 작업이 완료되기 까지 걸린 시간은 각각 97.90ms, 186.20ms에 비해, 실제 콘텐츠가 다운로드 되는데 걸린 시간은 4.44ms와 1.62ms로 작업 시간에 대한 확연한 차이를 알 수 있습니다.
따라서, 요청이 잦아질 경우 리소스를 요청하는데에 걸리는 시간은 기하급수적으로 늘어나며, 그렇기 때문에 최적화를 위해서는 처음 말했던 것처럼 요청의 개수를 줄이고, 리소스를 합치는 것이 필요합니다.
말을 좀 거창하게 한 것 같지만, 사실 그다지 어렵진 않습니다.
바로, 스프라이트 기법(CSS Sprites)과 Webpack과 같은 모듈 번들러(Module Bundler)를 사용하여 여러 파일을 하나의 파일로 통합하는 것입니다.
그 중 스프라이트 기법은 조각난 이미지 파일들을 하나로 병합한 후, 이를 배경으로 처리하는 것을 말합니다.
다시 말해, 여러 이미지 파일을 일일히 불러오는 것이 아니라, 한 이미지 파일로 통합한 후 Background-Position을 이용하여 사용자에게 실제로 보여지는 위치를 다르게 하는 것이죠.
현재, 국내 유명 포털엔진 및 SNS에서도 이를 적극 활용하고 있는데요. 아래 사진을 통해 확인해 볼 수 있습니다!
1. 네이버 (Naver)
2. 다음 (Daum)
3. 페이스북 (Facebook)
자바스크립트의 경우를 좀 더 예로 들자면, 흔히 개발할 때 style 파일은 <head /> 부분에, script 파일은 <body />의 최하단 부분에 위치 시켜야 한다는 말을 자주 들어 보셨을 겁니다.
기본적으로, 브라우저가 페이지를 렌더링하려면 먼저 HTML 마크업을 파싱하여 DOM을 빌드해야 합니다.
하지만 다음 그림과 같이, 브라우저가 파싱을 하다가 스크립트 파일을 만날 경우, 스크립트 파일을 요청하고 다 불러와지는 동안 구문에 대한 분석을 중단하게 되는데, 이것이 우리가 흔히 말하는 렌더링 블록킹(Rendering Blocking) 현상입니다. 당연히 렌더링이 계속해서 블록될 시 페이지의 첫 렌더링 시간은 지연될 수 밖에 없으며, 이는 곧 좋지 않은 사용자 경험으로 이어지게 됩니다.
이와 같은 이유 때문에, style과 script 파일을 지정된 곳에 위치시켜야 한다는 것이고, 좀 더 나은 페이지의 성능을 위해 간단하지만 필수적이라고 할 수 있습니다.
말이 계속 딴 길로 새는 것 같은데... 어쨌든 정리를 해보자면, Request에 가장 큰 영향을 끼치는 것은
네트워크의 커넥션 리소스이며, Request의 호스트 개수에는 제한이 있기 때문에 Request의 개수가 많아질 경우, 콘텐츠를 다운로드 하는 시간보다 전체 리소스를 불러오는 시간이 훨씬 더 길다는 것입니다.
물론 이 부분은 커넥션을 유지한 채로 통신하는 HTTP 2.0에서는 신경을 쓰지 않아도 되며, HTTP 1.1에서만 해당되는 내용이기 때문에 그냥 가볍게 읽어보시면 좋을 듯 합니다~
글 읽어주셔서 감사하고, 피드백은 언제나 환영입니다!
+ 이미지 Lazy Loading에 관한 이해를 돕기 위해 깃허브 레포를 생성하였습니다.
한 번 확인해보시면 좋을 듯 합니다 :D