JS - Call Stack에 대하여

1. Call Stack이란?

Call Stack은 자바스크립트가 함수 실행을 핸들링하는 방법 중 하나이다.

자바스크립트는 실행해햐하는 함수들을 Stack 위에 올린다. 

다르게  말하자면 Call Stack 은 자바스크립트 엔진이 현재 실행 중인 함수실행 대기 중인 함수를 관리하는 구조이다.

 

자바스크립트는 함수를 스택위에 올려놓고 합수가 실행이 끝나면 스택에서 제거(pop)한다.

이를 간단한 예제를 통해서 확인하면 다음과 같다.

 

 

2. 예제

function three() {
  console.log("i love js");
}

function two() {
  three();
}

function one() {
  two();
}

function zero() {
  one();
}

zero();

위 코드를 실행한 뒤 크롬 개발자 도구를 통해서 call stack을 하나하나 따라가보도록하자.

 

먼저 가장먼저 실행되는 zero() 함수가 callStack에 들어가 있다. 

 

그다음 zero()에서 호출하고 있는 one()가 callstack에 들어가 있다.

이런식으로 함수가 종료되기전까지는 callstack에 들어가 있게된다.

 

 

모든함수가 들어간뒤

 

실행되고 나면 callStack에서 제거된다.

 

 

이런식으로 자바스크립트에서 말하는 Call Stack이란 함수의 호출을 기록하는 자료구조로서 

우리가 어떤 함수를 실행시키는 것은 스택위에 무언가를 push() 하는 것이고 그 함수가 실행이 완료되면 스택의 맨위가

pop() 되는 것이다.

 

실행 순서

  1. zero() 호출 → Call Stack: [zero]
  2. zero() 안에서 one() 호출 → [zero, one]
  3. one() 안에서 two() 호출 → [zero, one, two]
  4. two() 안에서 three() 호출 → [zero, one, two, three]
  5. three() 실행 완료 → three 제거 → [zero, one, two]
  6. two 실행 완료 → [zero, one]
  7. one 실행 완료 → [zero]
  8. zero 실행 완료 → [] (스택이 비어짐)

 

3. Call Stack에서 자주 발생하는 오류

가장 흔하게 발생하는 오류는 StackOverflow 에러이다.

function repeat() {
  repeat(); // 자기 자신을 무한히 호출
}
repeat();

 

 

위 코드는 repeat 함수가 끝나지 않고 계속 push → push → push... 하다가

"Maximum call stack size exceeded" 오류가 발생한다.

 

 

 

4. 비동기 코드와 Call Stack

자바스크립트는 싱글스레드 언어이기 때문에,  한 번에 하나의 Call Stack만 가진다.

즉, 하나의 Call Stack에서 두개 이상의 함수를 동시에 실행하는 것은 불가능하다.

 

function foo() {
  console.log("foo 시작");
  bar();
  console.log("foo 끝");
}

function bar() {
  console.log("bar 실행");
}

foo();

 

 

자바스크립트 엔진은 동시에 foo와 bar를 병렬로 실행하지 않는다.

 

setTimeout은 Call Stack이 아니라 Web API / Task Queue로 빠져나갔다가,
Call Stack이 비면 이벤트 루프(Event Loop) 를 통해 다시 들어오기 때문인데

그렇다면 여기서 Web API/ Task Queue, Event Loop 3가지 키워드에 대해서 정리할 필요가 있다.

 

✅ Web API

브라우저나 Node.js 환경이 제공하는 비동기 작업 처리 영역.

 

✅ Task Queue (Callback Queue)

완료된 비동기 작업의 콜백 함수들이 대기하는 줄.
여기 있는 함수들은 바로 실행되지 않고, Call Stack이 비었을 때 이벤트 루프에 의해 실행 기회가 주어진다.

 

✅ Event Loop

Call Stack과 Task Queue를 감시하는 관리자.
Call Stack이 비면 Task Queue에서 콜백을 꺼내 Call Stack에 넣어 실행시킨다.

 

왜 이렇게 설계되었을까?

만약 Call Stack이 차 있는 동안 콜백을 억지로 집어넣으면?
→ 기존 코드 실행이 꼬이고, 동시 실행 문제(멀티 스레드에서 흔한 race condition)가 발생한다.

그래서 "Call Stack이 비었을 때만 실행" 한다는 규칙이 설정하게 되었다.

이벤트 루프는 이 규칙을 지키면서도, 비동기 작업들을 순서대로 다시 실행할 수 있게 해주는 교통정리 역할을 한다.