Programming Language/Javascript

[Javacript] 동기와 비동기, 이벤트 루프와 태스크 큐

ggyongi 2025. 2. 23. 22:49

 

 

동기 처리
코드를 순차적으로 실행하는 방식
앞의 작업이 완료될 때까지 다음 작업은 실행되지 않고 대기함
직관적이고 코드 흐름을 이해하기 쉬우나, 오래 걸리는 작업이 전체 프로그램을 차단할 수 있음

console.log("A");

function syncTask() {
  for (let i = 0; i < 1000000000; i++); // 오래 걸리는 작업
  console.log("B");
}

syncTask();
console.log("C");

// 출력 결과:
// A → (작업이 끝난 후) B → C


비동기 처리
특정 코드의 실행이 끝날 때까지 기다리지 않고 다음 코드를 즉시 실행하는 방식
오래 걸리는 작업(네트워크 요청, 타이머 등)을 백그라운드로 넘기고, 그동안 다른 작업이 실행됨
코드 흐름이 멈추지 않아 전체 프로그램의 성능이 향상됨

console.log("A");

setTimeout(() => {
  console.log("B");
}, 1000); // 1초 후 실행

console.log("C");

// 출력 결과:
// A → C → (1초 후) B

 

싱글 스레드
한 번에 하나의 작업만 처리할 수 있는 구조
JavaScript는 기본적으로 싱글 스레드 언어로, 하나의 콜 스택을 사용하여 작업을 순서대로 처리함
하나의 작업이 완료될 때까지 다음 작업이 실행되지 않고 대기함

특징
코드를 직관적이고 예측 가능하게 실행함
하나의 긴 작업이 끝나지 않으면 나머지 작업들이 모두 차단되는 단점이 있음
비동기 처리를 통해 싱글 스레드의 한계를 극복함

 

 

 

이벤트 루프를 통해 싱글 스레드의 한계를 극복

 

콜 스택
실행 컨텍스트가 추가되고 제거되는 스택 자료구조
함수가 호출되면 함수 실행 컨텍스트가 순차적으로 콜 스택에 푸시되어 순차적으로 실행됨
가장 최근에 추가된 함수가 가장 먼저 실행 완료(LIFO 구조)되어 스택에서 제거됨


객체가 저장되는 메모리 공간
콜 스택의 실행 컨텍스트는 힙에 저장된 객체를 참조함
원시 타입 데이터는 콜 스택 내에 바로 저장되고, 객체 타입(객체, 함수, 배열 등)은 힙에 별도로 저장된 후 참조만 콜 스택에서 관리함

태스크 큐
비동기 함수의 콜백 함수 또는 이벤트 핸들러가 실행되기 전에 일시적으로 대기하는 공간
JavaScript 엔진의 콜 스택이 비어 있을 때 태스크 큐에 있는 작업들이 콜 스택으로 이동하여 실행됨

이벤트 루프
콜 스택과 태스크 큐를 계속해서 모니터링하며 작업을 관리하는 루프
콜 스택이 비어 있을 때 태스크 큐에 대기 중인 함수가 있으면, 이벤트 루프는 순차적으로 태스크 큐에서 콜백 함수를 콜 스택으로 이동시켜 실행함
이를 통해 자바스크립트가 싱글 스레드임에도 마치 여러 작업이 동시에 처리되는 것처럼 보이게 함

Web APIs
브라우저가 제공하는 기능(자바스크립트 엔진 외부에 위치함)
자바스크립트가 싱글 스레드의 한계를 극복하도록 비동기 작업(타이머, HTTP 요청, DOM 이벤트 등)을 대신 처리해 줌
작업 완료 후 그 결과로 실행될 콜백 함수를 태스크 큐에 추가하여 이벤트 루프가 처리하도록 전달함


주의할 점
브라우저는 멀티 스레드 방식으로 동작함
JavaScript 엔진(콜 스택과 힙을 관리)은 싱글 스레드로 동작하지만, 이는 브라우저 전체가 아니라 JavaScript 엔진만의 특성임
비동기 작업(타이머, HTTP 요청, DOM 이벤트 등)은 브라우저의 Web APIs가 별도의 멀티 스레드 환경에서 처리함
따라서 JavaScript 코드 자체는 싱글 스레드로 동작하지만, 브라우저 환경 전체는 멀티 스레드로 동작하기 때문에 비동기 처리가 가능함

정리
JavaScript 엔진: 싱글 스레드
브라우저(Web APIs, 이벤트 루프, 렌더링 등): 멀티 스레드
이러한 구조 덕분에 JavaScript가 싱글 스레드임에도 불구하고 비동기 처리가 가능함