setTimeout
과 setInterval
는 기본적으로 무언가를 일정 간격을 두고 실행하도록 만들어주는 스케줄링 메서드 입니다.
두 녀석 다 반환값으로 Timer Identifier
를 반환해서 clearTimeout(timerId)
, clearInterval(timerId)
의 매개변수로 걸어놓았던 스케줄링을 취소할 수 있습니다.
저는 둘의 가장 큰 차이점은 한 번
만 하냐 무한번
반복하냐 라고 알고 있었습니다.
하지만 setTimeout
으로도 setInterval
과 같은 기능을 수행할 수 있다고 합니다.
바로 중첩 setTimeout
방식을 사용하면 된다고 합니다.
let timerId = setTimeout(function tick() {
alert("째깍");
timerId = setTimeout(tick, 2000); // ----(1)-----
}, 2000);
(1)
로 표시한 줄은 첫 스케줄링이 실행을 종료하면 다음 호출을 스케줄링 하는 방식으로 매번 자기 자신을 호출함으로써 무한번
수행시킬 수 있습니다.
이렇게 중첩 setTimeout
을 이용하는 방법은 setInterval
을 사용하는 방법보다 다른 복잡한 상황들을 유연하게 처리할 수 있다고 합니다.
5초 간격으로 서버에 요청을 보내 데이터를 얻는다고 가정해 봅시다. 서버가 과부하 상태
라면 요청 간격을 10초
, 20초
, 40초
등으로 증가시켜주는게 좋을 겁니다.
let delay = 5000;
let timer = setTimeout(function request() {
...요청 보내기...
if(서버 과부하로 인한 요청 실패) {
// 요청 간격을 늘립니다.
delay *= 2;
}
timerId = setTimeout(request, delay);
}, delay);
이처럼 동적으로 delay
를 변화시키면서 유연하게 처리할 수 있습니다.
중첩 setTimeout
은 시간 지연 간격을 보장하지만 setInterval
은 시간 지연을 보장하지 않습니다.
100ms
마다 스케줄링한 함수를 호출한다고 가정해봅시다.
그 결과는 그림과 같습니다. setInterval
로 호출한 함수는 지연 시간속에 함수를 실행하는 데 소모되는 시간
도 포함시킨다고 합니다.
하지만 함수를 실행하는데 소모되는 시간이 명시한 지연 시간보다 길 땐 어떤 일이 발생할까요?
이런 경우는 에러가 발생하진 않고
엔진이 함수의 실행이 종료될 때까지 기다리다 종료가 되면 스케줄러를 확인하고 지연시간이 지났으면 바로
다음 호출을 시작한다고 합니다.
반면 중첩 setTimeout
은 함수 실행 시간을 포함하지 않고 함수의 실행이 끝나고 난 뒤 다음 함수 호출에 대한 계획이 세워지기 때문에 지연시간이 보장된다고 합니다.
setTimeout
과 setInterval
의 콜백함수로 넘기면, 함수에 대한 내부 참조가
새롭게 만들어지고 이 참조 정보는 스케줄러
에 저장됩니다. 따라서 해당 함수를 참조하는 것이 없어도 가바지 컬렉션의 대상이 되지 않습니다. 즉 스케줄러가 함수를 호출할 때까지 함수는 메모리에 유지
된다고 합니다.
setInterval
의 경우는 clearInterval
이 호출되기 전까진 함수에 대한 참조가 메모리에 유지되기 때문에 가령 외부 렉시컬 환경을 참조하는 함수가 있다고 하면 이 함수가 존재하는 이상 외부 렉시컬 환경 또한 가비지 컬렉션의 대상이 되지 않아 실제 함수가 차지했어야 하는 공간보다 더 많은 메모리 공간이 사용된다고 합니다.
따라서 스케줄링할 필요가 없어진 함수는 아무리 작더라도 취소하도록 합시다.