호출 스케쥴링 (타이머 함수) 이해하기

Jiumn·2023년 4월 27일

JavaScript 대탐험

목록 보기
13/18

setTimeoutsetInterval 함수는 비동기 함수로서 특정 시간 후에 또는 주기적으로 함수를 실행해주는 타이머 함수다.

개념만 알고 있을 뿐 자주 써보지 않아서 setTimeout 함수를 setInterval처럼 동작하게 만드는 방법을 떠올리는 게 어려웠다. 우선 타이머 함수와 호출 스케링에 대해 정확하게 이해하기 위해 정리해본다.


호출 스케쥴링

호출 스케쥴링은 일정 시간이 지난 후에 원하는 함수를 예약 실행(호출)할 수 있게 하는 것이다.

setTimeout 함수와 setInterval 함수를 사용하여 구현할 수 있다.

setTimeout

let timerId = setTimeout(함수, 실행 전 대기 시간)
  • 함수: 실행하고자 하는 함수
  • 실행 전 대기 시간: 밀리 초 = 1/1000초

* 대기 시간 뒤에 함수에 전달할 인수들을 포함할 수 있는데 IE9 이하에서 지원하지 않는다.

어떤 메시지를 1초 후에 경고창으로 노출하는 동작을 자바스크립트로 만들어보자.

function sayHi() {
	alert('안녕하세요.')
}

setTimeout(sayHi, 1000)

'안녕하세요'라는 경고창을 띄우는 sayHi라는 함수가 setTimeout으로 전달되어 1초 후에 실행된다.

또는 함수를 따로 선언하지 않고 setTimeout 함수 안에 화살표 함수로 전달할 수도 있다.

setTimeout(() => alert('안녕하세요.'), 1000)

그런데 setTimeout 함수를 실행하면 콘솔에서 특정한 숫자가 반환되는 것을 알 수 있다.

이 숫자는 뭘 의미하는 걸까?

반환된 값은 타이머 식별자(timer identifier)다. clearTimeout의 인자로 타이머 식별자를 전달하면 타이머를 취소할 수 있다.

const timerId = setTimeout(() => {
  console.log('Hello World!');
}, 1000)

clearTimeout(timerId)

위와 같이 setTimeout 함수를 timeId라는 변수에 할당하면 타이머 식별자를 저장할 수 있다. 그리고clearTimeout 안에 타이머 식별자를 전달하면 해당 타이머를 중지할 수 있는 것이다.

setInterval

setInterval은 이름에서 알 수 있는 것처럼 어떤 함수를 주기적으로 호출한다. setTimeout과 마찬가지로 함수와 주기적으로 호출할 시간을 전달하면 된다.

setTimout으로도 setInterval을 구현할 수 있다.

let timerId = setInterval(() => alert('째깍'), 2000);

이 코드를 setTimeout으로만 작성하면 다음과 같다.

let timerId = setTimeout(function tick() {
	alert('째깍')
	timerId = setTimeout(tick, 2000)
}, 2000)

setTimeout 함수를 timerId에 할당한다. setTimeout 함수의 인자로는 tick 함수와 2000밀리 초를 전달한다. tick 함수 안에서는 alert('째깍')을 노출한 후 timerId 함수에 setTimeout 함수를 재할당한다. 따라서 setTimeout 함수 안에서 실행된 tick 함수가 다시 timerId 함수에 재할당되어 tick 함수를 2초 후에 실행하는 작업을 반복하게 된다.

이를 중첩 setTimeout 함수라고 부른다.

중첩하지 않고 함수를 따로 선언하는 방법도 있다.

function tick() {
	alert('째깍')
	setTimeout(tick, 2000)
}
setTimeout(tick, 2000)

tick 함수를 선언하고 tick 함수 내부에서 setTimeout 함수를 호출한다. 이때 setTimeout 함수 안에서 tick 함수를 2초 후 실행하도록 인자를 전달한다.

setTimeout 함수를 호출하고 인자로 tick 함수와 2000밀리초를 전달한다. 2초에 한 번씩 tick 함수가 실행되는 것을 알 수 있다.

포인트는 setTimeout 함수가 호출하는 함수 내부에서 다시 setTimeout 함수를 호출해야 한다는 점이다.

중첩 setTimeout과 setInterval의 차이

그렇다면 setTimeout 함수로 setInterval을 구현하면 무슨 차이가 있을까?

중첩 setTimeout 함수는 지연 간격을 보장하지만, setInterval 함수는 보장하지 않는다.

예를 들어, 100밀리 초마다 func(i++) 함수를 실행하는 setInterval 함수가 있다.

이 경우, func 호출 사이의 지연 간격이 실제 명시한 간격보다 짧아진다. 왜냐하면 func를 실행하는 데 소모되는 시간도 지연 간격에 포함시키기 때문이다.

setTimeout 함수의 경우, 지연 시간이 보장된다.

이전 함수의 실행이 종료된 이후에 다음 함수 호출에 대한 계획이 세워지기 때문이다.

타이머 함수와 타이머 취소 함수를 함꼐 사용한 예제를 하나 더 살펴보자.

from에 명시한 숫자부터 to에 명시한 숫자까지 출력해주는 함수 printNumbers(from, to)를 만들어보세요. 숫자는 일 초 간격으로 출력되어야 합니다.

function printNumber(from, to) {
  let current = from;

  const timerId = setInterval(() => {
    console.log(current);

    if (current == to) {
      clearInterval(timerId);
    }
    current++;
  }, 1000);
}

printNumber(1, 5); // 1 2 3 4 5

이때 current++는 if문 이후에 작성해야 한다. 그래야 1초부터 5초까지 모두 출력된 다음 if문이 true로 반환되어 타이머가 중지되기 때문이다.

참고 자료

https://ko.javascript.info/settimeout-setinterval
렛츠 기릿 자바스크립트

profile
Back-End Wep Developer. 꾸준함이 능력이다. Node.js, React.js를 주로 다룹니다.

0개의 댓글