빠른 비교
setTimeout(runOnce, 1000);
setImmediate(flushAfterIo);
queueMicrotask(flushAfterSync);타이머 종류
타이머에서 먼저 구분해 둘 대표 형태는 아래 네 가지입니다.
- 한 번만 미루기:
setTimeout(fn, ms) - 고정 주기 반복:
setInterval(fn, ms) - I/O 뒤 체크 단계로 미루기:
setImmediate(fn) - 현재 동기 작업 직후 정리:
queueMicrotask(fn)
반복 예약
setInterval이 위험해지는 경우
setInterval(async () => {
await fetchStatus();
}, 1000);이 패턴은 작업 시간이 1초보다 길어지면 호출이 밀리거나 겹쳐 보이기 쉽습니다. 그래서 "비동기 반복 작업"은 재귀 setTimeout이 더 안전합니다.
async function poll() {
try {
await fetchStatus();
} finally {
setTimeout(poll, 1000);
}
}즉시 실행 지점
setTimeout(0)과 setImmediate
둘 다 "지금 당장 아님"이라는 점은 같지만, 이벤트 루프에서 끼어드는 위치가 다릅니다. 특히 I/O 콜백 안에서는 setImmediate가 더 의도에 맞는 경우가 많습니다.
즉 여기서는 단순 타이머 API보다 이벤트 루프 phase를 어디에 끼워 넣을지까지 함께 봅니다.
마이크로태스크
microtask는 더 앞선다
queueMicrotask(() => console.log("microtask"));
setTimeout(() => console.log("timeout"), 0);microtask는 현재 동기 흐름이 끝난 직후 비워집니다. 그래서 timer보다 먼저 보입니다.
언제 무엇을 예약할까
타이머를 고를 때 볼 점
- 비동기 반복이면 재귀
setTimeout - 경량 고정 반복이면
setInterval - 즉시 뒤 정리는 microtask
- I/O 직후는
setImmediate - shutdown 시 타이머 해제까지 같이 본다
주의할 점
타이머 문제는 "몇 ms 후 실행"보다 "이 작업이 끝나기 전에 다음 작업이 예약돼도 괜찮은가"를 먼저 물어야 합니다. 이 질문에 아니오라면 setInterval보다 재귀 setTimeout 쪽이 맞습니다.
참고 링크
1 sources