[꼼꼼한 개발자] 꼼코더
[JS] - 자바스크립트 동작 원리 간단하고 쉽게 이해하기(콜스택, 이벤트 루프, 태스크 큐) 본문
🧹 간단 정리
- JS 엔진: 자바스크립트 코드를 읽고, 해석하고, 실행하는 프로그램
- 싱글 스레드 : 한 번에 하나의 작업만 처리 가능한 개념.
- Web API : 한 번에 여러 작업이 가능한 비동기 처리 도우미. (브라우저/Node가 제공)
- 예) setTimeout, fetch, DOM 이벤트, Node의 fs, http 등
- 콜스택(Call Stack) : 함수 실행이 쌓이는 스택. 실행 끝나면 빠져나옴.
- 태스크 큐(Task Queue) : 완료된 Web API(비동기)의 속에 있는 콜백 함수가 대기하는 공간
- 이벤트 루프(Event Loop) : (콜스택 비어있음 확인 후) 태스크 큐에서 대기하던 콜백을 꺼내 콜스택으로 전달
위 내용만 봐서는 모르는 게 당연합니다!
아래에 정말 정말 재밌고 쉽게 설명했으니 꼭! 확인해 보세요!
(개념 훝고 -> 맨 마지막 영상을 보시면 완벽하게 이해할 수 있어요!)
☕️ 자바스크립트는 싱글 스레드 - 우리 카페는 바리스타가 1명
브라우저 속에 있는 자바스크립트 엔진은 자바스크립트 코드를 읽고 실행합니다.
다만 싱글 스레드이기에 동시에 실행하지 못하고 한 줄씩 차례대로 처리해야 하죠.
그래서 자바스크립트는 싱글 스레드 언어라고 불립니다.

👨🏻🍳 비유설명
마치 카페에 바리스타(JS 엔진)가 한 명뿐인 상황과 같습니다.
- 손님이 커피 주문하면 → 바리스타는 바로 커피를 만듭니다.
- 동시에 다른 손님들이 주문하여도 동시에 만들 수 없이 한 사람씩 차례대로 처리해야 하죠.
- 👉 결국, 중요한 건 바리스타(JS 엔진)가 주문(함수)을 차례대로 실행하는 것입니다.
- (??? : 내가 아는 바리스타는 동시에 음료 여러개 만들던데요?!!?)
📚 콜스택(Call Stack) - 할 일 모음 집
콜스택(Call Stack)은 실행할 함수가 담겨있는 공간입니다.
먼저 들어온 요소가 나중에 나가는 ‘스택 구조(LIFO)’이죠.
- 함수 실행 → 스택에 push, 실행 종료 → 스택에서 pop

👨🏻🍳 비유설명
스택은 바리스타(JS 엔진)의 할 일 메모지 모음집 같은 존재입니다.
- “아메리카노 만들기” 메모 붙임(push) → 끝나면 메모 떼기(pop)
- “라떼 만들기” 메모 붙임(push) → 끝나면 메모 떼기(pop)
- 👉 결국, 콜스택(할 일 모음집)은 바리스타(JS 엔진)가 어떤 일들을 처리 중인지 확인하는 공간입니다.
🧑🏻🍳 비동기 처리(Web API) - 만능 알바생 등장이요
이전에 JS 엔진(바리스타)은 싱글 스레드이기에 한 번에 하나의 일만 처리할 수 있다고 했는데..
만약 콜스택(할 일 메모지)에 ‘긴 작업(예: 오래 걸리는 계산)’이 쌓여 있다면?
👉 그동안 버튼 클릭 이벤트나 모달 열기 같은 동작이 전혀 처리되지 않습니다.
즉, 화면이 “먹통”처럼 멈춘 것처럼 보이게 되죠.
🔹 비유하자면, 바리스타가 너무 바빠서 손님 주문이 줄줄이 쌓여 있는 상황과 같습니다.
이럴 때 필요한 게 비동기 처리!
비동기 처리를 활용하면 동시에 여러 일을 효율적으로 처리할 수 있습니다.
- 비동기 처리 종류 : Web API(setTimeout, fetch), DB 요청, 파일 읽기 등..
- (다만, 이 글에서는 Web API를 이용한 비동기 처리만 다루겠습니다!)
😎 (번외) Web API 목록 - 만능 알바생의 능력치
setTimeout, DOM 이벤트, fetch… 등
- setTimeout → “3초 뒤에 실행해 줘”라고 알바생(Web API)에게 맡김
- fetch → 서버에 요청 보내고, 응답 오면 알려줌
- addEventListener → 클릭이 발생할 때까지 계속 기다려줌
이렇게 하면 ‘메인 스레드(JS 엔진)’는 다른 일을 처리하면서도, 나중에 일이 끝났을 때 다시 실행할 수 있습니다.

👨🏻🍳 비유설명
바리스타는 한번에 하나의 일만 처리가 가능하기에 주방 알바생(Web API)에게 도움을 요청합니다.
- “2분 뒤에 샌드위치 만들어줘(setTimeout)“라고 부탁 후 바리스타는 다른 주문을 처리할 수 있어요.
- 주방 알바생이 2분 후 시간이 되면 “다 됐습니다!” 하고 픽업대에 올려놓습니다.
- 🧑🏻🍳 알바생 : “다 만들었고 픽업대(task Queue)에 올려놓을테니 나머지 작업(콜백함수)은 대신해주세요!"
📨 태스크 큐(Task Queue)
1. Web API가 작업을 마무리 후
2. 그 속에 있는 콜백 함수(남은 작업)를 태스크 큐에 올려 차례대로 올려놓습니다.
3. 콜백 함수들은 올려진 순서대로 실행될 차례를 기다리며 대기합니다.
- 대기하는 이유? => 콜스택이 비워지기 전에는 실행이 불가하기 때문.
- 큐는 먼저 들어온 요소가 먼저 나가는(FIFO) 구조입니다.

👨🏻🍳 비유설명
- 알바생(Web API)이 완료 후 남은 작업(콜백함수)들을 ‘픽업대(Task Queue)’에 올려놓았네요.
- 남은 작업(콜백 함수)은 바로 바리스타에게 가지 않고 '픽업대(Task Queue)'에 줄 서서 대기합니다.
- 왜냐고요? 아직도 바리스타(Call Stack)의 일이 끝나지 않았기 때문이죠!
- (??? : 바리스타 아직까지도 아메리카노 만들고 있네)
- (??? : 우리 팀 바리스타 뭐 함?)
👴🏽 이벤트 루프(Event Loop) - 악덕 매니저 등장 (바리스타 퇴사각)
이벤트 루프(Event Loop)는 2가지 역할을 가지고 있습니다.
- 콜스택이 비어 있는지 확인
- 비어 있으면 태스크 큐(Task Queue)에서 대기 중인 콜백 함수를 하나씩 콜스택(Call Stack)에 전달
중요한 점은 항시적으로 확인하는 것이 아닙니다!
- 처리해야 할 태스크가 있는 경우: 먼저 들어온 태스크부터 순차적으로 처리
- 처리해야 할 태스크가 없는 경우: 잠들어 있다가 새로운 태스크가 추가되면 다시 '1'로 돌아감

👨🏻🍳 비유설명
- 매니저(Event Loop)는 평소에는 꾸벅꾸벅 졸고 있습니다.😪
- 바리스타(Call Stack)가 모든 일을 마무리하고 손이 비면, 얼른 픽업대(Task Queue)에 있는 샌드위치(콜백 함수) 1개를 가져와 바리스타에게 전달합니다.
- 바리스타는 남은 작업(콜백 함수)인 샌드위치를 데우며(함수 실행) 작업을 계속 진행합니다.
- (??? : 어제 그 바리스타분 왜 안 보이시지?)
(이제 얼추 개념은 이해했으니 예제 코드를 보면서 확인해 봅시다.)
🧑🏻💻 예제 코드 - 자바스크립트 동작 순서(JavaScript event loop video)
예제 코드 확인 후 영상 아래 설명을 참고해 주세요!!
설명 부분을 반복해서 보다 보면 완벽히 이해가 되실 겁니다!
// 함수 선언 영역
function First() { console.log('1') }
function Second() { console.log('2') }
function Third() { console.log('3') }
// 함수 실행 영역
First();
setTimeout(Second, 5000);
Third();
이해하기 쉽게 비유도 참고해 봅니다!
- 🏚️ 브라우저 = JS 엔진이 있는 곳 = 카페 = 바리스타의 소속
- 🤯 JS 엔진 = 바리스타 = Call Stack 속 작업(함수) 실행자
- 🙋🏻♂️ JS 함수 = 손님의 주문 = First(), Second(), Third(), console.log()
- 📚 Call Stack = 할 일 모음 집 = 함수가 모여져 있는 곳 *원시값 변수도 저장되는 공간이지만 여기선 패스!
- 🧑🏻🍳 Web Apis = 알바생(도우미) = 비동기 작업 처리자
- 🗳️ Task Queue(CallBack Queue) = 픽업대 = 비동기 함수 속 인자(콜백 함수)의 대기 공간 = Call Stack에 전달될 콜백함수
- 🔄 event Loop = 카페 매니저 = Task Queue에 콜백 함수를 Call Stack에 전달 = 바리스타 괴롭히는 사람

1. First() 실행
- First() 호출 → 콜스택에 First() push → 콜스택에서 First() 실행
- console.log('1') 호출 → 콜스택에 console.log push → console.log('1') 실행 → 콘솔에 1 출력
- console.log 실행 완료 → 콜스택에서 console.log pop
- First() 실행 완료 → 콜스택에서 First() pop
2. setTimeout(Second, 5000) 실행
- setTimeout(Second, 5000) 호출 → 콜스택에 setTimeout push
- 콜스택에서 setTimeout 실행 → 브라우저(Web API)에 “5초 뒤에 Second 실행” 요청
- Web API는 타이머를 설정하고, setTimeout 실행 완료 → 콜스택에서 setTimeout pop
- Web API 영역에서 5초 카운트다운 시작
3. Third() 실행
- Third() 호출 → 콜스택에 Third() push → 콜스택에서 Third() 실행
- console.log('3') 호출 → 콜스택에 console.log push → console.log('3') 실행 → 콘솔에 3 출력
- console.log 실행 완료 → 콜스택에서 console.log pop
- Third() 실행 완료 → 콜스택에서 Third() pop
4. 5초 후 (Web API → Task Queue 이동)
- Web API의 타이머 종료 → Second 함수(콜백)를 태스크 큐(Task Queue)에 넣음
- 콜스택이 비어 있을 때까지 대기
5. 이벤트 루프(Event Loop), Second() 실행
- 이벤트 루프 콜스택 비어 있음 확인
- 태스크 큐에서 Second 함수 꺼내 → 콜스택에 push → 콜스택에서 Second() 실행
- 내부 console.log('2') 호출 → 콜스택에 console.log push → console.log('2') 실행 → 콘솔에 2 출력
- console.log 실행 완료 → 콜스택에서 console.log pop
- Second() 실행 완료 → 콜스택에서 Second() pop
👁️ 개발 시 고려할 점
🚫 콜스택(Call Stack)을 바쁘게 하지 말자
- 콜스택에서 오래 걸리는 작업(예: 무한 루프, 복잡한 계산, 대량의 DOM 조작 등)이 쌓이면 → 다른 이벤트가 처리되지 못합니다.
👉 긴 작업은 잘게 나누어 처리하거나(setTimeout, requestIdleCallback, Web Worker 사용), 메인 스레드를 막지 않도록 분리해 보세요!
🚫 태스크 큐(Task Queue)를 바쁘게 하지 말자
- 태스크 큐는 완료된 비동기 작업(콜백 함수)이 줄 서는 공간입니다.
- 너무 많은 setTimeout, setInterval, 이벤트 핸들러가 동시에 쌓이면 큐가 과부하될 수 있습니다.
- 그러면 실행이 지연되고, UI 반응이 늦어져서 사용자가 느끼기에 '버벅거린다'는 느낌을 줍니다.
👉 불필요한 이벤트 리스너 남발을 피하고, 이벤트 최적화(debounce, throttle) 기법을 활용해 보세요!
👋🏻 마무리
잘 이해가 되셨나요..? 워낙 방대한 개념이라 Micro task Queue, Promise 등은 다루지 않았고
일부 개념들은 간단하게 설명하고 넘어간 부분들이 있기에 걱정은 되지만 이 글을 통해서 JS 동작 흐름을 잡는데 도움이 되었으면 좋겠네요!
'간단하고 쉽게 > JavaScript' 카테고리의 다른 글
| [JS] - 함수 선언식과 함수 표현식이란? 간단하고 쉽게 이해하기(예제코드, 함수 선언식과 함수 표현식의 차이점, var 함수 표현식 호이스팅 에러 이유) (0) | 2024.01.20 |
|---|---|
| [JS] - TDZ(Temporal Dead Zone)이란? 간단하고 쉽게 이해하기 (예제코드, 임시 사각 지대란?) (0) | 2024.01.20 |
| [JS] - var, let, const의 차이점 간단하고 쉽게 이해하기 (예제코드) (0) | 2024.01.20 |
| [JS] - 스코프란? 간단하고 쉽게 이해하기 (예제코드, 글로벌 스코프,블록 레벨 스코프, 함수 스코프, 스코프 체인) (0) | 2024.01.20 |
| [JavaScript] - encodeURIComponent()란? 간단하고 쉽게 이해하기 (0) | 2023.05.02 |