본문 바로가기
Programming/자바스크립트

[자바스크립트] 호출 스케줄링

by 코딩하는 랄로 2023. 10. 31.
728x90

호출 스케줄링이란?

호출 스케줄링이란 이름 그대로 함수의 호출(실행)을 계획(스케줄링)한다는 것이다. 즉, 사용자가 원하는 일정 시간이 지난 후, 또는 일정시간마다 특정 함수를 실행할 수 있도록 하는 것이 호출 스케줄링인 것이다.  이를 위한 메소드로 setTimeout, setInterval을 사용할 수 있고, 해당 메소드의 작업은 비동기로 처리된다.

 

사실은 setTimout, setInterval는 자바스크립트에서 제공하고 있는 메소드가 아니다!! 동기 언어인 자바스크립트는 스스로 비동기 작업을 처리할 수 없기 때문이다. 그렇다면, setTimeout 과 setInterval는 누가 제공하는 메소드일까? 브라우저 창의 관리자 도구를 열어 콘솔 창에 다음과 같이 윈도우를 입력하면,

 

아래와 같이 윈도우 객체의 setTimeout, setInterval 메소드를 발견할 수 있다.

즉, setTimout, setInterval 함수는 자바스크립트 엔진에서 동작하는 메소드가 아닌, 브라우저(Web API)에서 동작하는 메소드인 것이다. 

 

 

 

setTimeout

setTimeout은 지정한 시간이 지난 후, 전달받은 콜백함수를 호출하여 실행시키는 메소드이다. setTimeout의 구성은 다음과 같다.

setTimeout(callback, delay, arg1, arg2, ...)

 

각 파라미터는 다음을 뜻한다.

  • callback : 시간이 지난 후, 실행시킬 함수
  • delay : 시간 설정 => ms 단위
  • arg1, arg2, ... : callback 함수에 들어갈 인수

이 중 callback 함수에 인수로 들어가는 arg1, arg2 는 IE9 이하에서는 지원하지 않는다. 간단한 예시를 통해 setTimeout의 사용법에 대해서 자세히 알아보자

// setTimeout
// delay => ms 단위 : 1s => 1000ms
setTimeout(function() {
    console.log('hi')
}, 2000);

const callback = function() { console.log('hello') }
setTimeout(callback, 3000)


const callbackArg = function(str) { console.log(`argument : ${str}`) }
setTimeout(callbackArg, 1000, 'javascript')

/*
결과 :
argument : javascript
hi
hello
*/

 

다양한 방법으로 선언한 함수를 setTImeout을 통해 실행시킨 뒤, 나온 결과이다. 결과를 통해서 알 수 있듯이, 비동기 작업을 통해, 시간 초에 맞게 해당하는 함수들이 동작한 것을 볼 수 있다. (callbackArg => callback => function() {} )

 

 

 

clearTimeout

clearTimeout은 setTimeout의 타이머를 종료시켜 해당 함수가 호출되지 않게 종료시켜버리는 메소드이다. clearTimeout은 타이머 식별자를 인수로 넘겨받는데, 이 값은 setTimeout가 호출되었을 때 반환하는 값이다.

let timerId = setTimeout( ... ) => timer identifier를 반환
clearTimeout(timerId) => 해당 식별자를 가지는 setTimeout을 종료
// clearTimeout
const callback = function() { console.log('hello') }
const timerId = setTimeout(callback, 3000)

clearTimeout(timerId)

위의 코드를 실행해보면, 타이머를 동작시키자마자 종료시키기 때문에 프로그램이 바로 종료되는 것을 확인 할 수 있다.

 

 

 

setInterval

setInterval 메소드는 setTimeout과 동일한 구문을 가진다. 차이점으로는 setTimeout은 일회성이지만, setInterval은 타이머가 종료될때 까지 일정시간마다 해당 함수를 호출한다는 것이다.

setInterval(callback, delay, arg1, arg2
// setInterval
const callback = function() { console.log('hello') }
setInterval(callback, 2000)

/*
hello
hello
hello
hello
hello
...
*/

 

 

 

clearInterval

setInterval의 타이머를 멈추기 위해서는 clearInterval  메소드를 사용하여 하고, 사용 방법은 setTimeout과 동일하다.

// clearInterval
const callback = function() { console.log('hello') }
const timerId = setInterval(callback, 2000)

//5초 뒤에 setInterval 종료
setTimeout(function() {
    clearInterval(timerId)
}, 5000)

/*
hello
hello
*/

5초 뒤에 setInterval의 타이머가 종료되기 때문에 hello 는 두번만 출력이 되는 것을 볼 수 있다.

 

 

 

setTimeout/setInterval 의 동작 원리

setTimeout과 setInterval의 동작 원리에 대해 이해하기 위해서는 콜백 함수 포스팅에서 다루었던, 자바스크립트가 비동기 작업을 처리하는 과정에 대해서 알아야 한다.

 

위에서도 간단하게 언급하였듯이, 자바스크립트는 Web API(브라우저)의 도움을 받아 비동기 작업을 처리를 하는데, 이 때 브라우저는 타이머가 끝났을 때, 함수의 실행까지 담당하지는 않는다.

 

함수의 실행은, 자바스크립트 엔진이 담당하기 때문에 브라우저는 call back queue에 해당 함수를 넘겨주게 되고 event loop가 자바스크립트의  call stack을 주시하다가 비어있는 순간에 call back queue에 함수를 넘겨주어 실행되는 것이다. 

 

그렇기 때문에, setTimeout, setInterval을 통해 설정한 타이머가 지났다고 하더라도, 콜백 함수가 바로 실행이 된다는 보장은 없는 것이다. (call back queue에서 기다리는 시간이 존재하고 이 시간은 마음대로 할 수 있는게 아님) 

 

이를 보다 잘 이해하기 위해서는 setTimeout의 시간을 0초로 설정한뒤 동작시켜보면 된다.

setTimeout(function() {
    console.log("거북이")
}, 0)

console.log('토끼')

 

위의 코드를 동작시켜보면, 토기가 거북이보다 빨리 출력되는 것을 볼 수 있다. 위의 코드의 과정은 다음과 같다.

  • setTimeout => call stack => Web API로 넘어감
  • call stack이 비게 됨 => 그 다음 문장인 console.log 실행 => 토끼 출력
  • webAPI가 바로 callback queue로 함수를 넘기지만, 이미 토끼는 출력 또는 실행중인 상태임
  • event loop가 call stack이 비게 될 때 함수를 넘김
  • console.log가 실행 => 거북이 출력

그렇기 때문에, setTimeout, setInterval을 사용할 때는 확실한 스케줄링을 통해 사용하여야 원하는 함수의 동작을 얻을 수 있다.

 

 

 

중첩 setTimeout

setTimeout은 다음과 같이 중첩하여 호출하는 것도 가능하다.

// nested setTimeout
setTimeout(function callback() {
    console.log("거북이")
    setTimeout(callback, 1000)
}, 1000)

 

위의 코드는, 얼핏보면 아래와 같은 코드처럼 보인다.

setInterval(function() {
    console.log('거북이')
}, 1000)

 

하지만, 두가지 코드는 완전히 다르다. 왜냐하면 setTimeout은 지연 간격을 보장하지만 setInterval은 보장하지 않기 떄문이다. 더 쉽게 설명하면, setInterval은 해당 시간이 지나고 함수를 호출하는 순간 스케줄링을 바로 시작하지만, setTimeout은 함수의 호출이 끝난 뒤 스케줄링을 하기 때문이다.

 

즉, setInterval 함수는 함수의 실행시간도 delay 시간에 포함되기 때문에 함수의 종료 시점부터 다음 함수의 실행 시점까지는 delay로 설정한 1초보다 짧은 시간인 것이다. 반면에 중첩 setTimeout을 사용할 경우, 거북이를 출력하고 그 다음 거북이가 출력되기 까지는 최소 1초는 보장한다.

 

그렇기 때문에, 중첩 setTimeout을 이용한 스케줄링이 보다 유연하다.

 

 

 

728x90