스크롤 이벤트를 배워본김에 무한 스크롤 페이지 같은걸 한번 만들어보기로 했다
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
ul {
padding-left: 0;
}
li {
list-style: none;
text-align: center;
background-color: black;
margin-bottom: 10px;
color: white;
font-size: 200px;
padding: 100px 0;
}
li:nth-child(2n) {
background-color: white;
color: black;
/* nth-child : 사이에 순서에 따라 요소를 선택한다
li의 2n 번째 형제를 선택 */
}
</style>
</head>
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</body>
</html>
// 스크롤을 끝까지 내리면 4번째 li를 생성해서 붙혀넣는다
// 전체 스크롤 높이 = document.querySelector('html').scrollHeight;
// 현재 화면에 보이는 높이 = document.querySelector("html").clientHeight;
// 처음부터 화면을 얼마나 내렸나 = window.scrollY;
const htmlH = document.querySelector("html").scrollHeight;
const $ul = document.querySelector("ul");
let count = $ul.children.length;
function infiniteScroll() {
let seeH = document.querySelector("html").clientHeight;
let thisH = window.scrollY;
if (seeH + thisH > htmlH - 10) {
let addList = document.createElement("li");
let $li = $ul.appendChild(addList);
count++;
$li.textContent = count;
}
}
window.addEventListener("scroll", infiniteScroll);
스크롤을 끝까지 내리면 카운터 변수에 1을 더한다
그 후 카운터 변수를 텍스트컨텐트로 쓰는 li 태그를 생성해서 ul 태그의 자식으로 넣는 방식이다
스크롤을 끝까지 내렸다는것을 감지하기 위해서는
현재 내가 보고있는 화면의 높이와 지금까지 얼마나 스크롤을 내렸는지의 수치의 합이
전체 스크롤 높이와 같아졌을경우 이지만 브라우저 마다 높이 계산방식이 다르고 오차의 가능성 때문에
-10 픽셀 정도의 여유를 주고 합이 더 크다면 스크롤을 끝까지 내렸다고 간주하기로 한다
확인이 쉽도록 짝수번째의 li 태그는 색 반전을 해줬다

위의 사진처럼 그냥 살짝 내렸을 뿐인데 무수히 많은 이벤트가 발생한다
스크롤 이벤트의 특징인데 이렇게 되면 리소스를 아주 많이 잡아먹는다
그렇기 때문에 시간 내에 과도한 이벤트 실행으로 인해 발생하는 성능 저하를 막기 위해
일정한 시간을 주기로 이벤트가 한 번만 실행되도록 제한한다
그중 대표적인 방법이 두 가지가 있는데
첫번째가 디바운싱(debouncing), 두번째로 쓰로틀링(throttling) 이 있다
let debouncing;
window.addEventListener("scroll", () => {
if (debouncing) {
clearTimeout(debouncing);
}
debouncing = setTimeout(infiniteScroll, 50);
});

setTimeout 은 특정 함수를 실행하기 전 딜레이 시간을 설정하는 함수이므로
일정시간 기다린 후 함수를 실행한다 그 동안의 타이머는 제거한다
타이머가 작동되고 있는 시간동안은 새로운 타이머 이벤트를 생성하지 않는다고 이해하면 된다
'특정시간 이후에 한번만' 이라는 키워드를 기억하면 좋다
let throttling;
window.addEventListener("scroll", () => {
if (!throttling) {
throttling = setTimeout(() => {
throttling = null;
infiniteScroll();
}, 200);
}
});

이벤트가 발생했을 때, 타이머가 비어있다면 타이머를 실행하고 함수 내에서 타이머를 null 값으로 초기화 해 준다. 이벤트가 동작하고 있을때는 이벤트 호출이 되지 않는다.
'일정한 간격으로 한번만' 이라는 키워드를 기억하면 좋다.


사진을 보면 정확하게 이해할 수 있다
이전 이벤트를 무시하는 것과 이후 이벤트를 무시하는 것의 차이이다
디바운싱
3초의 시간을 설정해두고,
3초 내에는 버튼이 눌려도 폭죽이 발사되지 않도록 조정해두었다.
마구 연타시 폭죽은 발사되지 않고 마지막 버튼을 떼는 순간 3초 뒤 발사된다.
쓰로틀링
일단 버튼이 눌리면 3초간 먹통이 된다.
그리고 3초 후에는 다시 폭죽이 발사되도록 초기화가 된다.
이제 버튼을 마구 연타를 해도 3초의 발사 간격을 보장해준다.
디바운싱은 어떤 특정한 요청의 묶음을 하나로 처리하고 싶을 때,
쓰로틀링은 과도한 연속된 요청을 끊고싶을 때 주로 쓴다고 한다
용도에 맞는 코드를 짜는 것은 물론 중요하지만 그것보다는
왜 써야 하는가를 아는것이 더 중요하다고 끊임없이 들어왔는데
이제 조금 이해가 되는 것 같다