이벤트 루프
The mechanism that handles asynchronous callbacks in JavaScript
— MDN Web Docs - Concurrency model and the Event Loop
"싱글 스레드의 탈을 쓴 악마 같은 병렬 사기극" 정작 메인 스레드 하나에서 무한 루프 한 번 돌면 웹 페이지 전체가 굳어버리는 건 비밀이다
1. 개요
자바스크립트 엔진의 핵심 구동 메커니즘이자, 싱글 스레드(Single Thread) 환경에서 동시성(Concurrency)을 가상으로 구현해 주는 일등 공신이다. 브라우저나 Node.js 환경에서 대기 중인 비동기 태스크들을 감시하며, 호출 스택(Call Stack)이 비는 즉시 대기열의 콜백 함수들을 스택에 밀어 넣는 무한 루프의 형태를 띤다.(...)
2. 싱글 스레드라면서 어떻게 멈추지 않는가?
웹 브라우저는 화면 렌더링, 네트워크 요청, 타이머 등 다양한 작업을 백그라운드에서 동시에 처리해야 한다. 자바스크립트는 싱글 스레드로 동작하므로, 무거운 작업을 직접 처리하면 브라우저가 완전히 멈춘다(Freeze). 이를 방지하기 위해 비동기 작업은 Web API로 던져버리고, 완료된 작업의 결과물(콜백)만 태스크 큐(Task Queue)에 줄 세운 뒤 이벤트 루프가 스택으로 배달하는 구조를 취한다. 결국 과로는 브라우저가 하고 자바스크립트는 생색만 내는 구조다.1
3. 관련 밈 및 드립
3.1. setTimeout(..., 0) 만능주의
자바스크립트 실행 순서가 꼬이거나 DOM이 아직 제대로 렌더링되지 않았을 때, 영혼 없이 setTimeout(() => { ... }, 0)으로 코드를 감싸 대충 해결해 버리는 실무진의 오랜 나쁜 습관을 풍자하는 밈이다. 놀랍게도 90%의 상황에서 이게 기적처럼 작동하기 때문에 근본 원인 분석을 영원히 포기하게 만든다.(...)
3.2. 마이크로태스크 감옥
Promise 체이닝을 끊임없이 재귀 호출하여 마이크로태스크 큐에 무한정 태스크를 채워 넣는 장난이다. 이 경우 일반 setTimeout을 비롯한 브라우저 화면 갱신이 완전히 차단되어 컴퓨터가 이륙하기 시작하는 진풍경을 볼 수 있다.
4. 여담
- 우선순위의 차별: 태스크 큐는 단 하나가 아니다.
Promise가 사용하는 마이크로태스크 큐(Microtask Queue)는 일반setTimeout이 들어가는 매크로태스크 큐(Macrotask Queue)보다 압도적인 우선순위를 가져서, 마이크로태스크가 마르지 않고 계속 들어오면 이벤트 루프는 다른 작업을 영원히 처리하지 못한다.(...) - setTimeout 0ms의 거짓말:
setTimeout(fn, 0)이라고 적어도 절대로 0ms 만에 실행되지 않는다. 브라우저 스펙상 최소 지연 시간(보통 4ms)이 존재할뿐더러, 호출 스택이 완전히 비어 있어야만 실행될 기회를 얻기 때문이다. - 렌더링 타이밍의 수수께끼: 이벤트 루프는 브라우저의 화면 주사율(보통 60Hz)에 맞춰 렌더링 파이프라인(Render Queue)을 실행할 타이밍도 조율한다. 이를 잘못 건드리면 화면이 미친 듯이 끊기는 대참사가 발생한다.