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

양주영·2021년 9월 10일
0

javascript

목록 보기
22/42

setTimeout


setTimeout() 함수는 일정시간이 지난 후 인자로 받은 함수를 한번 실행해주는 메서드이다.

문법 :

let timerId = setTimeout(func|code, [delay], [arg1], [arg2], ...)
  • func | code
    실행하고자 하는 코드로, 함수 또는 문자열 형태이다. 대개는 이 자리에 함수가 들어간다. 하위 호환성을 위해 문자열도 받을 수 있게 해놓았지만 추천하지 않는다.

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

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

함수 실행 후 return 값으로 상수를 리턴한다.
함수 실행 때마다 1씩 추가되어 리턴한다.
응용 : setTimeout의 리턴 값이 상수, 상수는 true 값을 이용하여 setTimeout의 조건을 넣을 수 있다.

예시1 :

function sayHi() {
  alert(‘Hello.);
}

setTimeout(sayHi, 1000);
//1초 후 sayHi()가 호출된다.

예시2 :

function sayHi(who, phrase) {
  alert( who + ' 님, ' + phrase );
}

setTimeout(sayHi, 1000, "홍길동", "안녕하세요."); // 홍길동 님, 안녕하세요.


💡 setTimeout에 함수를 넘길 때, 함수 뒤에 ()을 붙이는 실수를 하지 말자

// 잘못된 코드
setTimeout(sayHi(), 1000);

setTimeout은 함수의 참조 값을 받도록 정의되어 있는데 sayHi()를 인수로 전달하면 함수 실행 결과가 전달되어 버린다. 그런데 sayHi()엔 반환문이 없다. 호출 결과는 undefined가 된다. 따라서 setTimeout은 스케줄링할 대상을 찾지 못해, 원하는 대로 코드가 동작하지 않는다.




setInterval


setInterval() 함수는 주기적으로 인자를 실행하는 함수이다.
setTimeout과 동일한 문법을 사용한다.

  • 보통 아래와 같이 사용한다.
function test() {
  console.log("Hello!");
}
setInterval(test, 3000);
  • 위 test 함수에 인자가 있다면?
function test(string) {
  console.log(string);
}
setInterval(function() {
  test("Hello!");
}, 3000);


clearInterval


clearInterval() 함수는 현재 진행되고 있는 함수의 진행을 멈추는데 쓰인다.

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

// 2초 간격으로 메시지를 보여줌
let timerId = setInterval(() => alert('째깍'), 2000);

// 5초 후에 정지
setTimeout(() => { clearInterval(timerId); alert('정지'); }, 5000);


중첩 setTimeout


무언가를 일정 간격을 두고 실행할 때 2 가지 방법
1. setInterval
2. 중첩 setTimeout

/** setInterval을 이용하지 않고 아래와 같이 중첩 setTimeout을 사용함
let timerId = setInterval(() => alert('째깍'), 2000);
*/

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

다섯 번째 줄의 setTimeout은 (*)로 표시한 줄의 실행이 종료되면 다음 호출을 스케줄링한다.
중첩 setTimeout을 이용하는 방법은 setInterval을 사용하는 방법보다 유연하다. 호출 결과에 따라 다음 호출을 원하는 방식으로 조정해 스케줄링 할 수 있기 때문이다.

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

let delay = 5000;

let timerId = setTimeout(function request() {
  ...요청 보내기...

  if (서버 과부하로 인한 요청 실패) {
    // 요청 간격을 늘립니다.
    delay *= 2;
  }

  timerId = setTimeout(request, delay);

}, delay);

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

두 예시를 비교해보자. setInterval을 이용한 예시

let i = 1;
setInterval(function() {
  func(i++);
}, 100);

setTimeout을 이용한 예시

let i = 1;
setTimeout(function run() {
  func(i++);
  setTimeout(run, 100);
}, 100);

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

setInterval을 사용하면 func 호출 사이의 지연 간격이 실제 명시한 간격(100ms)보다 짧아진다!

그 이유는 func을 실행하는데 ‘소모되는’ 시간도 지연 간격에 포함시키기 때문이다.
만약 func을 실행하는데 걸리는 시간이 명시한 지연 간격보다 길 경우, 엔진이 func의 실행이 종료될 때까지 기다려준다. 종료되면 스케줄러 확인하고, 지연 시간이 지난 후 다음 호출을 바로 시작한다.

한편, 중첩 setTimeout을 이용하면 다음과 같이 실행 흐름이 이어진다.
중첩 setTimeout을 사용하면 명시한 지연(여기서는 100ms)이 보장됩니다.



대기 시간이 0인 setTimeout


대기 시간이 0인 setTimeout(setTimeout(func, 0) 혹은 setTimeout(func))을 사용하면 ‘현재 스크립트의 실행이 완료된 후 가능한 한 빠르게’ 원하는 함수를 호출할 수 있다.

setTimeout(() => alert("World"));

alert("Hello");

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




참조 : https://ko.javascript.info/settimeout-setinterval

profile
뚜벅뚜벅

0개의 댓글