IntersectionObserver API란?

iamsummer__·2020년 5월 10일
0

이미지 lazyloading이나 infinite scroll을 구현할 때 getBoundClientRect()을 사용하여 엘리먼트의 offset값을 확인하였습니다.
이러한 메소드들은 메인 쓰레드에서 진행되며 동기적 레이아웃 스레싱을 발생시켜 성능이 저하될 수 있습니다.

IntersectionObserver API
viewport 또는 타켓이 되는 엘리먼트의 교차 영역에 대한 변화를 비동기적으로 감지할 수 있습니다.

callback과 option값만 넘겨주면 됩니다.

option의 종류에 대해 알아보겠습니다.

root 는 타겟을 감싸는 element 이며 null인 경우 viewport을 의미합니다.
rootmargin은 위 root의 margin으로 사용할 값 입니다. px이나 %로 줄 수 있으며 기본값은 0입니다.
threshold는 target element 가 root 와 몇 % 교차했을 때, callback 을 실행할지 결정하는 값 입니다
값은 float 값으로 된 단일값 또는 배열값을 입력할 수 있고 0.0 부터 1.0 까지의 부동 소수점 값을 입력합니다.

Callback은 타켓이 되는 엘리먼트의 visibility가 threshold만큼 도달했을 때 호출될 함수입니다.

그러나 지원하는 브라우저가 제한이 있습니다. IE는 현재 지원을 하지 않아 pollyfill을 사용해야합니다.

IntersectionObserver API을 사용하여 이미지 lazyloading을 구현해보았습니다.
기존에 getBoundClientRect()을 사용했을 때와 성능테스트를 진행해보았습니다.

getBoundClientRect()을 사용한 경우

  imagelazy() {
    $(document)
      .find('img')
      .each((idx, item) => {
        const $this = $(item);

        if (this.isView($this)) {
          const hrefVal = $this.data('src');
          $this.attr('src', hrefVal).removeAttr(this.props.selector);
        }
      });
  }

  isView($this) {
    const rect = $this[0].getBoundingClientRect();
    const isTop = parseInt(rect.top) + this.props.top >= 0;
    const isBottom =
      parseInt(rect.bottom) + this.props.bottom <= $(window).height();
    const isLeft = parseInt(rect.left) + this.props.left >= 0;
    const isRight = parseInt(rect.right) + this.props.right <= $(window).width();
      return isTop && isBottom && isLeft && isRight;
  }

IntersectionObserver API 사용한 경우

 init() {
    const images = document.querySelectorAll('img');
    const options = {
      root: null,
      threshold: 0.8
    };
    const lazyLoadIO = new IntersectionObserver(this.lazyLoadImage, options);
    images.forEach(image => {
      lazyLoadIO.observe(image)
    });
  }

  lazyLoadImage(entries, observer) {
  // entry.isIntersecting 프로퍼티는 관찰하고자 하는 DOM 객체가
설정한 root 와 threshold 만큼 교차했는지에 대한 true/false 값 입니다
    entries.forEach(entry => {
      const { target } = entry;
      if (entry.isIntersecting) {
        const $target = $(target);
        const hrefVal = $target.data('src');
        $target.attr('src', hrefVal).removeAttr('data-src');
        // observer 해제
        observer.unobserve(target);
      }
    })
  }

위의 스크린샷을 보면 성능적인 측면에서 IntersectionObserver API가 더 우수하다는 것을 확인할 수 있습니다.

github에 들어가면 소스를 확인할 수 있습니다.

profile
개발하는 프론트엔드개발자

0개의 댓글