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()
함수는 주기적으로 인자를 실행하는 함수이다.
setTimeout
과 동일한 문법을 사용한다.
function test() {
console.log("Hello!");
}
setInterval(test, 3000);
function test(string) {
console.log(string);
}
setInterval(function() {
test("Hello!");
}, 3000);
clearInterval()
함수는 현재 진행되고 있는 함수의 진행을 멈추는데 쓰인다.
함수 호출을 중단하려면 clearInterval(timerId)
를 사용하면 된다.
// 2초 간격으로 메시지를 보여줌
let timerId = setInterval(() => alert('째깍'), 2000);
// 5초 후에 정지
setTimeout(() => { clearInterval(timerId); alert('정지'); }, 5000);
무언가를 일정 간격을 두고 실행할 때 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(setTimeout(func, 0)
혹은 setTimeout(func)
)을 사용하면 ‘현재 스크립트의 실행이 완료된 후 가능한 한 빠르게’ 원하는 함수를 호출할 수 있다.
setTimeout(() => alert("World"));
alert("Hello");
실행하면 얼럿창에 ‘Hello’와 ‘World’가 순서대로 출력되는 것을 확인할 수 있다.