JavaScript - setTimeout과 setInterval을 이용한 호출 스케줄링

Leejunyoung·2022년 8월 31일
0

JavaScript

목록 보기
49/49

setTimeout과 setInterval을 이용한 호출 스케줄링

일정 시간이 지난 후에 원하는 함수를 예약 실행(호출)할 수 있게 하는 것을 '호출 스케줄링(scheduling a call)'이라고 한다.

호출 스케줄링을 구현하는 방법은 두 가지가 있다.

  • setTimeout을 이용해 일정 시간이 지난 후에 함수를 실행하는 방법
  • setInterval을 이용해 일정 시간 간격을 두고 함수를 실행하는 방법
  • 자바스크립트 명세서엔 setTimeout과 setInterval가 명시되어있지않다. 하지만 시중에 나와 있는 모든 브라우저, Node.js를 포함한 자바스크립트 호스트 환경 대부분이 이와 유사한 메서드와 내부 스케줄러를 지원한다.


    setTimeout

    문법 :

    매개변수 :
    func | code
    실행하고자 하는 코드로, 함수 또는 문자열 형태이다. 대개는 이 자리에 함수가 들어간다.
    하위 호환성을 위해 문자열도 받을 수 있게 해놓았지만 추천하는 방법은 아니다.

    delay
    실행 전 대기 시간으로, 단위는 밀리초(millisecond, 1000밀리초 = 1초)이며 기본값은 0이다.

    arg1, arg2 ...
    함수에 전달할 인수들로, IE9 이하에선 지원하지 않는다.

    예시를 통해 setTimeout을 어떻게 쓸 수 있는지 알아보자. 아래 코드를 실행하면 1초 후에 sayHi()가 호출된다.

    아래와 같이 함수에 인수를 넘겨줄 수도 있다.

    setTimeout의 첫 번째 인수가 문자열이면 자바스크립트는 이 문자열을 이용해 함수를 만든다.

    아래 예시가 정상적으로 동작하는 이유이다.

    그런데 이렇게 문자열을 사용하는 방법은 좋지 않은 방법이다. 되도록 다음 예시와 같이 익명 화살표 함수를 사용하자.


    clearTimeout으로 스케줄링 취소하기

    setTimeout을 호출하면 '타이머 식별자(timer identifier)'가 반환된다. 스케줄링을 취소하고 싶을 땐 이 식별자(아래 예시에서 timerId)를 사용하면 된다.

    스케줄링 취소하기 :

    아래 예시는 함수 실행을 계획해 놓았다가 중간에 마음이 바뀌어 계획해 놓았던 것을 취소한 상황을 코드로 표현하고 있다. 예시를 실행해도 스케줄링이 취소되었기 때문에 아무런 변화가 없는 것을 확인할 수 있다.

    예시를 실행하면 alert 창이 2개가 뜨는데, 이 얼럿 창을 통해 브라우저 환경에선 타이머 식별자가 숫자라는 걸 알 수 있다. 다른 호스트 환경에선 타이머 식별자가 숫자형 이외의 자료형일 수 있다.
    참고로 Node.js에서 setTimeout을 실행하면 타이머 객체가 반환된다.

    스케줄링에 관한 명세는 따로 존재하지 않는다. 명세가 없기 때문에 호스트 환경마다 약간의 차이가 있을 수밖에 없다.


    setInterval

    setInterval 메서드는 setTimeout과 동일한 문법을 사용한다.

    문법 :

    인수 역시 동일하다. 다만, setTimeout 이 함수를 단 한번만 실행하는 것과 달리 setInterval은 함수를 주기적으로 실행하게 만든다.

    함수 호출을 중단하려면 clearInterval(timeId)을 사용하면 된다.

    다음 예시를 실행하면 메시지가 2초 간격으로 보이다가 5초 이후에는 더 이상 메시지가 보이지 않는다.


    중첩 setTimeout

    무언가를 일정 간격을 두고 실행하는 방법에는 크게 2가지가 있다. 하나는 setInterval을 이용하는 방법이고, 다른 하나는 아래 예시와 같이 중첩 setTimeout을 이용하는 방법이다.

    다섯 번째 줄의 setTimeout은 (*)로 표시한 줄의 실행이 종료되면 다음 호출을 스케줄링한다.

    중첩 setTimeout을 이용하는 방법은 setInterval을 사용하는 방법보다 유연하다. 호출 결과에 따라 다음 호출을 원하는 방식으로 조정해 스케줄링 할 수 있기 때문이다.

    5초 간격으로 서버에 요청을 보내 데이터를 얻는다고 가정해보자. 서버가 과부하 상태라면 요청 간격을 10초, 20초, 40초 등으로 증가시켜주는 게 좋다.

    아래는 이를 구현한 의사 코드이다.

    CPU 소모가 많은 작업을 주기적으로 실행하는 경우에도 setTimeout을 재귀 실행하는 방법이 유용하다. 작업에 걸리는 시간에 따라 다음 작업을 유동적으로 계획할 수 있기 때문이다.

    중첩 setTimeout을 이용하는 방법은 지연 간격을 보장하지만 setInterval은 이를 보장하지 않는다.

    아래 두 예시를 비교해보자. 첫 번째 예시에선 setInterval을 이용하였다.

    두 번째 예시에선 중첩 setTimeout을 이용하였다.

    첫 번째 예시에선, 내부 스케줄러가 func(i++)를 100밀리초마다 실행한다.

    그림을 보면 setInterval을 사용하면 func 호출 사이의 지연 간격이 실재 명시한 간격 (100ms)보다 짧아지는 것을 확인 할 수 있다.
    이는 func을 실행하는 데 '소모되는' 시간도 지연 간격에 포함시키기 때문이다. 지극히 정상적인 동작이다.

    그렇다면 func을 실행하는 데 걸리는 시간이 명시한 지연 간격보다 길 때 어떤 일이 발생할까

    이런 경우는 엔진이 func의 실행이 종료될 때까지 기다려준다. func의 실행이 종료되면 엔진은 스케줄러를 확인하고, 지연 시간이 지났으면 다음 호출을 바로 시작한다.

    따라서 함수 호출에 걸리는 시간이 매번 delay 밀리초보다 길면, 모든 함수가 쉼 없이 계속 연속 호출 된다.

    한편, 중첩 setTimeout을 이용하면 다음과 같이 실행 흐름이 이어진다.

    중첩 setTimeout을 사용하면 명시한 지연(여기서는 100ms)이 보장된다.
    이렇게 지연 간격이 보장되는 이유는 이전 함수의 실행이 종료된 이후에 다음 호출에 대한 계획이 세워지기 때문이다.


    대기 시간이 0인 setTimeout

    setTimeout(func, 0)이나 setTimeout(func)을 사용하면 setTimeout의 대기 시간을 0으로 설정할 수 있다.

    이렇게 대기 시간을 0으로 설정하면 func을 '가능한 한' 빨리 실행할 수 있다. 다만, 이때 스케줄러는 현재 실행 중인 스크립트의 처리가 종료된 이후에 스케줄링한 함수를 실행한다.

    이런 특징을 이용하면 현재 스크립트의 실행이 종료된 '직후에' 원하는 함수가 실행될 수 있게 할 수 있다.

    예시를 실행하면 얼럿창에 'Hello'와 'World'가 순서대로 출력되는 것을 확인할 수 있다.

    예시에서 첫 번째 줄은 '0밀리초 후에 함수 호출하기’라는 할 일을 '계획표에 기록’해주는 역할을 한다. 그런데 스케줄러는 현재 스크립트(alert 함수)의 실행이 종료되고 나서야 '계획표에 어떤 할 일이 적혀있는지 확인’하므로, Hello가 먼저, World은 그다음에 출력된다.

    profile
    안녕하세요

    0개의 댓글