
JS는 단일 스레드 기반으로 동작한다. 즉, 한 순간에 하나의 실행 흐름만 가질 수 있고, 실행할 함수들은 콜 스택(Call Stack) 에 쌓였다가 위에서부터 하나씩 처리된다. 이런 구조에서는 어떤 작업이 오래 걸리면 그동안 스택이 막혀 화면 렌더링, 클릭 처리 같은 UI 작업까지 멈추는(“blocking”) 문제가 생긴다.
그래서 브라우저는 JS 엔진(V8 등) 바깥에, 시간이 걸리는 일을 대신 처리하는 별도의 실행 환경을 제공한다. 흔히 Web APIs라고 부르는 영역인데, 여기에는 setTimeout 같은 타이머, 네트워크 요청(fetch/XHR), DOM 이벤트 감지(click/scroll), 파일/스토리지 접근 등이 포함된다. 핵심은, JS 엔진이 직접 오래 걸리는 일을 “병렬로 처리”하는 게 아니라, 브라우저가 제공하는 기능에 작업을 맡기고 JS는 다음 코드를 계속 실행할 수 있게 만든다는 점이다.
이때, “비동기 작업의 결과를 언제 다시 JS 코드로 돌려보낼지”를 조율하는 것이 이벤트 루프(Event Loop) 다. JS 코드가 비동기 API를 호출하면, 해당 작업은 브라우저(Web APIs) 쪽에서 진행되고, 완료 시점에 브라우저는 그 후속 작업(콜백 실행)을 대기열(queue) 에 올려둔다. 이벤트 루프는 계속해서 다음 조건을 확인한다.
- 콜 스택이 비어 있는지(현재 실행 중인 JS가 없는지)
- 비어 있다면, 대기열에 있는 작업 중 실행 가능한 것을 콜 스택으로 옮길지
이 과정을 반복하면서, 브라우저는 “JS 실행(콜 스택)”과 “비동기 작업 완료 후 후속 처리(큐)”를 연결한다. 정리하면 흐름은 다음과 같다.
- 콜 스택: 동기 코드 실행(즉시 실행되는 함수들)
- Web APIs: 시간이 걸리거나 이벤트 기반인 작업 처리(타이머, 네트워크, 이벤트 감지 등)
- 큐(대기열): 완료된 비동기 작업의 “후속 실행(콜백)”이 줄 서는 곳
- 이벤트 루프: 스택이 비면 큐에서 하나를 꺼내 스택으로 넣어 실행시키는 조율자
큐는 보통 하나가 아니라 성격이 다른 여러 종류가 있다. 예를 들어 Promise.then 같은 작업은 일반 콜백(타이머 등)보다 우선순위가 높은 큐(마이크로태스크 큐) 로 들어가고, setTimeout 같은 타이머 콜백은 태스크(매크로태스크) 큐로 들어간다. 그래서 실행 순서가 “작성 순서”가 아니라, 어떤 큐에 들어가느냐에 따라 달라질 수 있다.
'Programming > Javascript, Typescript' 카테고리의 다른 글
| Debounce와 Throttle이란 (0) | 2026.01.09 |
|---|---|
| JavaScript 디자인 패턴 (0) | 2025.07.06 |
| 리액트, 뷰를 안 쓰는 개발자들은 뭐 쓸까? 프론트엔드 프레임워크 알아보기 (0) | 2025.06.27 |
| [Jest] 특정 테스트 파일만 제외하고 실행하고 싶을 때 (0) | 2025.02.15 |
| [프론트엔드 테스팅] Yoni Goldberg의 JavaScript Testing Best Practices (0) | 2024.04.15 |
댓글