Next.js
팁
동기화 안되면 만능 setTimeout을 쓰는 이유 - Event Loop
중년개발자
@loxo
24일 전
30
동기화 안되면 만능 setTimeout을 쓰는 이유
- 자바스크립트 이벤트 루프의 뒷골목 이야기
1️⃣ 프롤로그: “왜 얘는 항상 마지막에 오지?”
어느 날, 신입 개발자 민수는 이런 코드를 짰다.
js
console.log("1번");
setTimeout(() => {
console.log("2번");
}, 0);
console.log("3번");민수의 머릿속 실행 순서 👇
1번 → 2번 → 3번
현실의 실행 결과 👇
1번 → 3번 → 2번
민수는 혼잣말을 한다.
“아니… 0ms 라며… 왜 제일 늦게 와…?”
이 순간이 바로 이벤트 루프의 세계로 입문하는 관문이다.
2️⃣ 무대 설정: 자바스크립트는 1명뿐인 식당이다 🍜
자바스크립트를 혼자 일하는 요리사라고 생각해보자.
- 주방에 요리사는 단 한 명
- 주문은 줄을 서서 처리
- 동시에 두 요리는 절대 불가
이 주방에는 세 가지 공간이 있다.
🧠 Call Stack (주방)
- 지금 당장 요리 중인 주문
- 동기 코드는 무조건 여기서 즉시 처리
🗂 Web API (대기실)
- 타이머, 네트워크, 이벤트 리스너 같은 외주 작업
- 요리사는 직접 안 하고 맡겨둠
🌀 Event Loop + Queue (복도)
- “주방 비었나요?”
- 비었으면 대기 중인 손님 하나 입장
3️⃣ 본론: setTimeout(0)은 왜 항상 마지막일까?
js
console.log("1번");
setTimeout(() => console.log("2번"), 0);
console.log("3번");🎬 실행 흐름 이야기
console.log("1번")→ 즉시 실행setTimeout→ Web API로 이동 후 Task Queue에 등록console.log("3번")→ 즉시 실행- Call Stack이 완전히 비면 Event Loop가 Task Queue 확인
- setTimeout 콜백 실행
❗ 핵심 진실
setTimeout(0)은 즉시 실행이 아니다
→ Call Stack이 완전히 비고 난 뒤 실행 예약
4️⃣ 개발자들이 만능 setTimeout을 쓰는 이유 😂
이유 1️⃣ 지금 말고, 조금만 있다가
js
setTimeout(() => {
doSomething();
}, 0);의미는 사실 이거다 👇
“지금 콜스택 끝난 다음에 실행해줘”
이유 2️⃣ DOM / 상태 / 렌더링 대기
js
setState(value);
setTimeout(() => {
readDOM(); // 이 시점엔 반영돼 있을 확률 ↑
}, 0);렌더링보다 한 박자 늦추는 트릭
이유 3️⃣ 왜 되는지는 모르겠지만 되긴 함
- 이벤트 루프의 순서를 이용한 사이드 이펙트
- 나중에 버그 폭탄 💣
5️⃣ Promise가 setTimeout보다 빠른 이유 ⚡
js
setTimeout(() => console.log("task"), 0);
Promise.resolve().then(() => console.log("microtask"));실행 결과
microtask → task
이유는 큐의 우선순위 때문이다
| 구분 | 큐 종류 | 실행 시점 |
|---|---|---|
| Promise.then | Microtask Queue | Call Stack 종료 직후, 최우선 |
| setTimeout | Task Queue | Microtask 전부 처리 후 |
👉 Microtask는 Event Loop가 다른 큐를 보기 전에 무조건 처리
6️⃣ 자주 보는 await 샘플 완전 정복
예제 1️⃣ await는 코드를 멈추는 게 아니다
js
async function run() {
console.log("A");
await Promise.resolve();
console.log("B");
}
run();
console.log("C");실행 결과
A → C → B
이유
await를 만나면 함수는 중단- 나머지는 Microtask로 등록
- 현재 Call Stack은 계속 실행됨
예제 2️⃣ await + setTimeout 조합
js
async function test() {
console.log(1);
await new Promise((resolve) => setTimeout(resolve, 0));
console.log(2);
}
test();
console.log(3);실행 결과
1 → 3 → 2
해설
- setTimeout은 Task Queue
- await 이후 코드는 그 Task가 끝난 뒤 Microtask로 실행
7️⃣ 실무 팁 요약 🎯
- ✔
Promise.then / await→ 빠른 다음 단계 - ✔
setTimeout→ 완전히 다음 턴 - ❌ 동기화 목적의 setTimeout 남용은 위험
8️⃣ 한 줄 엔딩 🎤
setTimeout은 시간을 재는 도구가 아니라,
“너 지금 할 일 다 끝나고 불러”라고 말하는 장치다.
그래서 오늘도 개발자들은 이렇게 말한다.
“흠… 이건 setTimeout 한 번 감싸자.”
그리고 이벤트 루프는 조용히 마지막 순서표를 들고 서 있다 🌀
#JavaScript#EventLoop#setTimeout#CallStack#WebAPI
댓글 0
Ctrl + Enter를 눌러 등록할 수 있습니다※ AI 다듬기는 내용을 정제하는 보조 기능이며, 최종 내용은 사용자가 확인해야 합니다.