이미지 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()을 사용했을 때와 성능테스트를 진행해보았습니다.
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;
}
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에 들어가면 소스를 확인할 수 있습니다.