CS

JavaScript 콜 스택(Call Stack)

KIMSANGHUN 2024. 11. 9. 17:53

Javascript
이 글은 자바스크립트를 기반으로 작성되었습니다


JavaScript Call Stack 이란?

자바스크립트에서 콜 스택(call stack)은 함수 호출을 관리하는 구조로, 함수가 호출될 때마다 해당 함수가 콜 스택에 추가되고, 함수 실행이 완료되면 콜 스택에서 제거되는 "LIFO(Last In, First Out)" 방식의 데이터 구조입니다.

 

콜 스택의 주요 동작 원리는 다음과 같습니다:

  1. 함수 호출 시 스택에 푸시(Push)
    자바스크립트 엔진이 특정 함수를 호출하면 해당 함수가 콜 스택에 추가됩니다. 이 함수가 실행 중이라면, 호출된 다른 함수도 콜 스택에 계속 추가됩니다.
  2. 함수 종료 시 스택에서 팝(Pop)
    함수 실행이 끝나면 해당 함수는 콜 스택에서 제거됩니다. 이때 호출된 순서의 반대로, 마지막에 호출된 함수부터 차례로 종료됩니다.

  3. 스택 오버플로(Stack Overflow)
    콜 스택에는 한계가 있습니다. 함수 호출이 무한 루프에 빠지거나 재귀 호출이 너무 깊어지면, 콜 스택이 꽉 차는 현상이 발생하는데, 이를 스택 오버플로라고 합니다. 스택 오버플로가 발생하면 프로그램은 멈추거나 에러가 발생합니다.

 

function first() {
  second();
  console.log("First function");
}

function second() {
  third();
  console.log("Second function");
}

function third() {
  console.log("Third function");
}

first();

 

위 코드가 실행될 때 콜 스택의 상태는 다음과 같습니다.

  1. first() 함수 호출 → 콜 스택에 first 푸시
  2. second() 함수 호출 → 콜 스택에 second 푸시
  3. third() 함수 호출 → 콜 스택에 third 푸시
  4. third 함수가 완료되면 콜 스택에서 제거됨
  5. second 함수가 완료되면 콜 스택에서 제거됨
  6. first 함수가 완료되면 콜 스택에서 제거됨

최종적으로 콜 스택은 비어 있는 상태가 되며, 프로그램이 종료됩니다.

 

 

실행결과

 

 

자바스크립트는 비동기 작업(예: setTimeout, HTTP 요청 등)을 처리하기 위해 이벤트 루프태스크 큐를 사용합니다. 비동기 함수는 콜 스택이 비었을 때 다시 콜 스택에 추가되어 실행됩니다. 이를 통해 자바스크립트는 단일 스레드임에도 불구하고 비동기적으로 여러 작업을 처리할 수 있습니다.

 

이벤트 루프(Event Loop)

이벤트 루프는 자바스크립트의 실행 흐름을 관리하는 메커니즘으로, 콜 스택과 태스크 큐를 모니터링하면서 비동기 작업이 언제 실행될지를 결정합니다. 이벤트 루프의 핵심 동작 방식은 다음과 같습니다.

  • 콜 스택이 비어 있는지 확인: 이벤트 루프는 콜 스택을 계속해서 모니터링합니다. 만약 콜 스택이 비어 있다면, 태스크 큐에 있는 작업 중 첫 번째 작업을 콜 스택에 넣어 실행합니다.
  • 무한 반복: 이벤트 루프는 콜 스택과 태스크 큐를 계속해서 확인하며, 콜 스택이 비어질 때마다 태스크 큐에서 작업을 가져와 처리하는 동작을 무한히 반복합니다.

이러한 과정을 통해 비동기 작업이 실행됩니다.

 

태스크 큐(Task Queue)

태스크 큐는 비동기 작업의 콜백 함수가 대기하는 큐로, 일반적으로 setTimeout, HTTP 요청, DOM 이벤트 등의 비동기 작업이 완료되면 해당 작업의 콜백 함수가 태스크 큐에 들어갑니다.

 

태스크 큐의 동작 원리

  • 비동기 작업이 완료되면 그 콜백 함수가 태스크 큐에 추가됩니다.
  • 태스크 큐에 추가된 콜백 함수는 콜 스택이 비어 있을 때 이벤트 루프에 의해 콜 스택으로 이동되어 실행됩니다.
  • 이때 태스크 큐는 FIFO(First In, First Out) 방식으로 작동하여, 먼저 완료된 작업의 콜백이 먼저 실행됩니다.

 

예시코드

console.log("Start");

setTimeout(() => {
  console.log("Timeout Callback");
}, 0);

console.log("End");

 

실행 과정

  1. console.log("Start")가 호출되어 콜 스택에 푸시되고 실행된 후 콜 스택에서 제거됩니다. 따라서 콘솔에 "Start"가 출력됩니다.
  2. setTimeout 함수가 호출되어 콜 스택에 푸시됩니다. 이 함수는 비동기 작업이므로, 콜백 함수는 바로 실행되지 않고 0ms 후에 태스크 큐에 추가됩니다.
  3. console.log("End")가 호출되어 콜 스택에 푸시되고 실행된 후 콜 스택에서 제거됩니다. 따라서 콘솔에 "End"가 출력됩니다.
  4. 이벤트 루프가 콜 스택이 비어 있음을 확인하고, 태스크 큐에서 대기 중인 setTimeout 콜백을 가져와 실행합니다. 따라서 "Timeout Callback"이 출력됩니다.

 

실행 결과

 

매크로 태스크와 마이크로 태스크

 

비동기 작업은 매크로 태스크(Macro Task)마이크로 태스크(Micro Task)로 분류됩니다.

  • 매크로 태스크: setTimeout, setInterval, I/O 작업 등이 있으며, 일반적인 비동기 작업입니다.
  • 마이크로 태스크: Promise.then, process.nextTick (Node.js) 등이 포함됩니다. 마이크로 태스크는 매크로 태스크보다 높은 우선순위를 가지며, 이벤트 루프가 콜 스택이 비었을 때 태스크 큐에서 매크로 태스크를 가져오기 전에 먼저 실행됩니다.

이벤트 루프는 마이크로 태스크 큐를 먼저 비운 다음 매크로 태스크 큐로 넘어갑니다.

이러한 이벤트 루프와 태스크 큐 메커니즘을 통해 자바스크립트는 비동기 작업을 효율적으로 처리하고, 동기적 코드를 방해하지 않으면서도 다양한 비동기 작업을 처리할 수 있습니다.