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번");

🎬 실행 흐름 이야기

  1. console.log("1번") → 즉시 실행
  2. setTimeout → Web API로 이동 후 Task Queue에 등록
  3. console.log("3번") → 즉시 실행
  4. Call Stack이 완전히 비면 Event Loop가 Task Queue 확인
  5. 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.thenMicrotask QueueCall Stack 종료 직후, 최우선
setTimeoutTask QueueMicrotask 전부 처리 후

👉 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 다듬기는 내용을 정제하는 보조 기능이며, 최종 내용은 사용자가 확인해야 합니다.