공부

lazy loading

출처 블로그


lazy loading이란?

  • 사용자가 웹 페이지를 열면 전체 페이지의 내용을 다운로드 받는다.
  • 만약 이용자가 전체 사진 갤러리를 다운로드했지만 첫번째 이미지만 본 후 사용자가 떠났을다면? 웹페이지에서는 메모리 및 대역폭 낭비가 발생한 것이다.
  • lazy loading이란 웹 및 응용 프로그램 개발에서 리소스를 미리 로드하는 대신 실제로 필요한 시점으로 로드하도록 지연시키는 기술이다.

장점

  • 성능향상 : 미리 다운받는 리소스가 적어지니깐 요청에서 렌더링까지의 시간이 줄어들고 페이지를 빠르게 사용 가능하다.
  • 비용절감

사용법

일반적인 로직

  • 이미지 태그에 src값 대신 data-src와 같은 data 어트리뷰트를 사용하여 실제 로드할 이미지 주소를 기입한다. (브라우저의 이미지 로드를 막음)
  • 이미지가 로드될 시기(주로 뷰 포트에 들어가면)가 되면 이미지를 로드한다.
  • 해당 이미지가 로드가 완료되면 data-src에 있는 주소값을 src값으로 셋팅하고 data-src는 삭제한다

방법 1) js 이벤트를 사용해서 이미지 로드 트리거

  • js scroll 이벤트로 이미지의 위치가 브라우저의 스크롤 높이보다 작다면 data-src를 src 값에 할당하여 이미지를 로드시킨다.

  • html

  <img src="https://ik.imagekit.io/demo/img/image1.jpeg?tr=w-400,h-300" />
  <img src="https://ik.imagekit.io/demo/img/image2.jpeg?tr=w-400,h-300" />
  <img src="https://ik.imagekit.io/demo/img/image3.jpg?tr=w-400,h-300" />
  <img class="lazy" data-src="https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-400,h-300" />
  <img class="lazy" data-src="https://ik.imagekit.io/demo/img/image5.jpeg?tr=w-400,h-300" />
  <img class="lazy" data-src="https://ik.imagekit.io/demo/img/image6.jpeg?tr=w-400,h-300" />
  <img class="lazy" data-src="https://ik.imagekit.io/demo/img/image7.jpeg?tr=w-400,h-300" />
  <img class="lazy" data-src="https://ik.imagekit.io/demo/img/image8.jpeg?tr=w-400,h-300" />
  <img class="lazy" data-src="https://ik.imagekit.io/demo/img/image9.jpeg?tr=w-400,h-300" />
  <img class="lazy" data-src="https://ik.imagekit.io/demo/img/image10.jpeg?tr=w-400,h-300" />
  • js
document.addEventListener("DOMContentLoaded", function () {
  var lazyloadImages = document.querySelectorAll("img.lazy")
  var lazyloadThrottleTimeout

  function lazyload() {
    if (lazyloadThrottleTimeout) {
      clearTimeout(lazyloadThrottleTimeout)
    }

    lazyloadThrottleTimeout = setTimeout(function () {
      var scrollTop = window.pageYOffset
      lazyloadImages.forEach(function (img) {
        if (img.offsetTop < window.innerHeight + scrollTop) {
          img.src = img.dataset.src
          img.classList.remove("lazy")
        }
      })
      if (lazyloadImages.length == 0) {
        document.removeEventListener("scroll", lazyload)
        window.removeEventListener("resize", lazyload)
        window.removeEventListener("orientationChange", lazyload)
      }
    }, 20)
  }

  document.addEventListener("scroll", lazyload)
  window.addEventListener("resize", lazyload)
  window.addEventListener("orientationChange", lazyload)
})
  • 처음 이미지 3개는 바로 로드하고 나머지는 lazy loading 적용된다

방법2 Intersection Observer API

  • intersection observer는 타겟 엘리먼트가 화면에 노출되었는지 여부를 간단하게 구독할 수 있는 api이다.
  • 스크롤 이벤트보다 성능상으로 유리하다고 한다.
document.addEventListener("DOMContentLoaded", function() {
  var lazyloadImages;    

  if ("IntersectionObserver" in window) {
    lazyloadImages = document.querySelectorAll(".lazy");
    var imageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          var image = entry.target;
          image.src = image.dataset.src;
          image.classList.remove("lazy");
          imageObserver.unobserve(image);
        }
      });
    });

    lazyloadImages.forEach(function(image) {
      imageObserver.observe(image);
    });
  } else {  
    var lazyloadThrottleTimeout;
    lazyloadImages = document.querySelectorAll(".lazy");

    function lazyload () {
      if(lazyloadThrottleTimeout) {
        clearTimeout(lazyloadThrottleTimeout);
      }    

      lazyloadThrottleTimeout = setTimeout(function() {
        var scrollTop = window.pageYOffset;
        lazyloadImages.forEach(function(img) {
            if(img.offsetTop < (window.innerHeight + scrollTop)) {
              img.src = img.dataset.src;
              img.classList.remove('lazy');
            }
        });
        if(lazyloadImages.length == 0) { 
          document.removeEventListener("scroll", lazyload);
          window.removeEventListener("resize", lazyload);
          window.removeEventListener("orientationChange", lazyload);
        }
      }, 20);
    }

    document.addEventListener("scroll", lazyload);
    window.addEventListener("resize", lazyload);
    window.addEventListener("orientationChange", lazyload);
  }
})
  • 하지만 Intersection observer를 지원하지 않는 브라우저(당연히 ie)도 있기 때문에 그땐 스크롤이벤트를 적용시켜야한다.

배경이미지의 경우

  • css의 백그라운드 이미지를 none으로 설정 후 뷰포트에 오면 바꿔주는 방식을 쓴다.
    #bg-image.lazy {
     background-image: none;
     background-color: #F1F1FA;
    }
    #bg-image {
    background-image: url("https://ik.imagekit.io/demo/img/image10.jpeg?tr=w-600,h-400");
    max-width: 600px;
    height: 400px;
    }
  • 위와 같은 예제에선 id가 bg-image인 요소에 lazy클래스를 추가시켜둔다.
  • 뷰 표트에오면 lazy 클래스 속성을 삭제시켜서 백그라운드 이미지가 none -> 이미지소스로 적용되게 한다.

그외 팁들 생략

'공부' 카테고리의 다른 글

실용적인 프론트엔드 테스트 전략 - 2  (0) 2020.12.09
실용적인 프론트엔드 테스트 전략 - 1  (0) 2020.12.09
프레젠테이션/컨테이너 컴포넌트  (0) 2020.12.08
타입스크립트  (0) 2020.12.07
리액트  (0) 2020.12.06