주제: Event Loop & Asynchronous Internal (이벤트 루프와 비동기 내부 구조)

그동안 async/await과 Promise를 수만 번 써오면서도, 정작 이놈들이 브라우저 안에서 어떤 순서로 줄을 서서 실행되는지는 대충 '비동기니까 나중에 되겠지'라고만 막연하게 생각했던 것 같다. 오늘 이벤트 루프의 설계도를 밑바닥부터 뜯어보니, 내가 짠 코드들이 왜 그런 순서로 움직였는지 비로소 퍼즐이 맞춰지는 기분이다. 5년 차라는 연차에 걸맞게 '동작 원리'를 아는 것이 얼마나 중요한지 새삼 깨달았다.
자바스크립트 엔진은 '싱글 스레드'라는 제약을 극복하기 위해 외주(Web API)와 철저한 대기열(Queue) 시스템을 활용한다.
[ 메인 엔진 (Stack) ] [ 외주 업체 (Web APIs) ]
│ │
함수 실행! (LIFO) ──────▶ 타이머, 네트워크 요청 등
│ (위임) │
▼ ▼
[ 이벤트 루프 (Event Loop) ] ◀─── 작업 완료 후 콜백 전달
│
▼
[ 대기열 (Queues) ]
1. Microtask Queue (VIP) : Promise, async/await (싹쓸이 처리)
2. Render Tree Update : UI 업데이트 (화면 그리기)
3. Task Queue (General) : setTimeout, setInterval (하나씩 처리)
이벤트 루프는 쉼 없이 돌면서 딱 네 가지만 확인한다. 이 우선순위가 실무의 핵심이다.
Promise.then 같은 애들이 기다리고 있다면, 큐가 완전히 빌 때까지 하나도 남김없이 Stack으로 옮겨서 실행한다.setTimeout 같은 콜백을 처리하는데, Microtask와 다르게 딱 하나의 task만 실행하고 다시 1번(Stack 확인)으로 돌아간다.setTimeout(0)이 0초가 아닌 이유: 아무리 0초라고 해도 얘는 'Task Queue'로 간다. 앞에 쌓인 Microtask(Promise)가 1만 개라면, 걔네가 다 처리될 때까지 얘는 절대로 실행될 수 없다. 즉, 지연 시간은 '실행 시점'이 아니라 'Task Queue에 들어가는 시점'을 의미한다.무거운 로직을 Microtask에 몰아넣지 말고 적절히 쪼개서 Task Queue로 분산시키는 전략이 필요할 것 같다.이벤트 루프의 '길'을 이해했으니, 이제 이 길 위에서 변수들이 어떻게 메모리를 점유하고 사라지는지(실행 컨텍스트와 호이스팅)를 파헤쳐 보도록 해보자.
이제 몇 년 내로 시니어 포지션으로 전환하려면 기본기가 더욱 탄탄해야 할 것 같다는 생각이 더욱 피부로 와닿게 되는 시간이었다. 끝.