어쩌다보니 iOS 개발자
Event Loop(이벤트 루프) 완전 정리 본문
✅ 결론부터
자바스크립트는 싱글 스레드이며,
이벤트 루프는 Call Stack이 비었을 때 대기 중인 작업을 실행하도록 조정하는 반복 제어 메커니즘이다.
비동기 작업은 JS 밖에서 병렬로 수행될 수 있지만, JS 코드 실행은 항상 단일 스레드에서 순차적으로 이루어진다.
🔎 그렇다면 왜 이벤트 루프를 알아야 할까?
비동기 실행 순서를 예측하고, 실제 버그를 해결하기 위해서다.
1️⃣ 실행 순서를 정확히 예측하기 위해
setTimeout(() => console.log("A"), 0);
Promise.resolve().then(() => console.log("B"));
왜 B가 먼저 실행될까?
이벤트 루프를 모르면 “그냥 그렇다”가 된다.
이벤트 루프를 이해하면:
Microtask → Task 순서 때문이라고 설명할 수 있다.
2️⃣ UI 멈춤(블로킹)을 이해하기 위해
while (true) {}
이 코드 한 줄이면:
- 버튼 클릭 안 됨
- 애니메이션 멈춤
- Promise 실행 안 됨
- setTimeout 실행 안 됨
이유는 간단하다.
Call Stack이 비지 않으면 이벤트 루프가 돌지 못하기 때문이다.
React Native에서도 JS Thread가 막히면 UI가 끊긴다.
이걸 이해하려면 이벤트 루프를 알아야 한다.
3️⃣ async / await를 제대로 이해하기 위해
await something();
console.log("done");
await는 코드를 멈추는 것이 아니라
나머지를 Microtask로 넘기는 것이다.
이걸 이해하면:
- 왜 await 이후 코드가 나중에 실행되는지
- 왜 병렬 처리를 위해 Promise.all이 필요한지
- 왜 루프 안에서 await를 쓰면 느려지는지
를 설명할 수 있다.
4️⃣ React / React Native 동작을 이해하기 위해
- 상태가 왜 바로 반영되지 않는가?
- 왜 setTimeout(0)이 완전히 즉시 실행되지 않는가?
- 왜 JS 연산이 길어지면 화면이 끊기는가?
이 모든 질문의 근본에는 이벤트 루프가 있다.
🎯 최종 정리
이벤트 루프를 이해한다는 것은
자바스크립트의 실행 모델을 이해하는 것이다.
그 결과:
- 실행 순서를 예측할 수 있고
- 비동기 버그를 줄일 수 있고
- UI 블로킹을 방지할 수 있으며
- 프레임워크 동작을 이해할 수 있다
원하면 글 전체를 더 다듬어서
👉 “입문자용 부드러운 설명 스타일”
👉 “기술 블로그 느낌의 구조적 설명 스타일”
👉 “면접 대비용 압축형 글”
중 하나로 톤을 맞춰서 완성본 만들어줄까요?
1. 자바스크립트는 싱글 스레드다
자바스크립트 엔진은 Call Stack 하나만 가진다.
console.log("A");
console.log("B");
이 코드는 절대 동시에 실행될 수 없다.
항상 A → B 순서로 실행된다.
2. 그런데 어떻게 비동기가 가능한가?
핵심은 이것이다:
JS 코드 실행은 싱글 스레드지만,
비동기 작업은 JS 밖에서 처리된다.
예를 들어:
- setTimeout → 브라우저/네이티브 타이머
- fetch → 네트워크 스택
- 파일 I/O → OS 레벨 처리
이 작업들은 JS 스레드가 아니라 **런타임 환경(브라우저/네이티브)**에서 병렬로 처리된다.
작업이 끝나면:
- 콜백이 Queue에 등록됨
- 이벤트 루프가 Call Stack이 비었을 때 실행
3. 이벤트 루프란 무엇인가?
이벤트 루프는 “공간”이 아니라 로직이다.
개념적으로는 다음과 같다:
while (프로그램이 살아있는 동안) {
if (CallStack이 비어있으면) {
Microtask 전부 실행
Task 하나 실행
}
}
즉,
대기 중인 작업을 언제 실행할지 결정하는 반복 제어 메커니즘
4. Call Stack / Microtask / Task 차이
🔹 Call Stack
- 현재 실행 중인 코드
- JS는 한 번에 하나만 실행
🔹 Microtask Queue
- Promise.then
- async/await 이후 코드
- queueMicrotask
특징:
- Call Stack이 비면 전부 실행
🔹 Task Queue (Macrotask)
- setTimeout
- setInterval
- I/O
- 이벤트 핸들러
특징:
- 한 번에 하나만 실행
5. 실행 순서의 핵심 규칙
이벤트 루프의 핵심 규칙:
동기 코드 실행
→ Microtask 전부 실행
→ Task 하나 실행
→ 반복
예시:
console.log("1");
setTimeout(() => console.log("2"), 0);
Promise.resolve().then(() => console.log("3"));
console.log("4");
출력 결과:
1
4
3
2
이유:
- 동기: 1, 4
- Microtask: 3
- Task: 2
6. async / await는 무엇을 하는가?
await는 실행을 멈추는 것이 아니라,
나머지 코드를 Microtask로 넘기는 문법적 설탕(syntax sugar)
예시:
async function test() {
console.log("1");
await Promise.resolve();
console.log("2");
}
test();
console.log("3");
출력:
1
3
2
await 뒤는 항상 Microtask에서 실행된다.
7. 그렇다면 비동기는 진짜 비동기인가?
정확한 표현은 이렇다:
작업 수행은 병렬일 수 있다.
JS 코드 실행은 절대 병렬이 아니다.
예를 들어 fetch는 병렬로 네트워크 요청을 수행하지만,
콜백 실행은 JS 스레드에서 순차적으로 이루어진다.
8. React Native 기준으로 보면
React Native도 기본적으로 JS Thread 하나에서 동작한다.
구조는 다음과 같다:
JS Thread
↑
이벤트 루프
↑
Native Modules / OS / Network
- 네트워크 요청 → 네이티브에서 병렬 처리
- 완료 → JS Queue에 등록
- JS Thread가 순차 실행
그래서:
- JS에서 무거운 연산을 하면 UI가 멈춘다
- 타이머도 지연된다
- Promise도 대기한다
왜냐하면 JS Thread는 하나뿐이기 때문이다.
'React Native 개발' 카테고리의 다른 글
| 클로저와 렉시컬 스코프란? (0) | 2026.02.13 |
|---|---|
| 호이스팅을 알아야 하는 이유는?? (0) | 2026.02.13 |
| Cursor로 React Native 개발을 해보자 (1) - 세팅 (3) | 2025.06.25 |