본문 바로가기
나의 개발일지/javascript

[javascript | JS] setTimeout()을 통해 호출 스택, 이벤트 루프 알아보기

by stella_gu 2022. 6. 29.

자바스크립트는 싱글 스레드이면서 어떻게 비동기 동작을 할까?

 

JS 비동기의 핵심, 이벤트 루프에 대해 알아보자.

자바스크립트 런타임 동작 원리

1. 메모리 힙 (Memory Heap) : 객체(object) 등 참조타입 데이터가 저장 되는 곳, 변수나 상수에 사용되는 메모리를 저장하는 곳.

 

2. 호출 스택 (콜 스택, Call Stack)

    • 함수의 '호출', 자료구조의 '스택'
    • 함수 호출 순서대로 쌓이고, 역순으로 실행됨.
    • 함수 실행이 완료되면 스택에서 빠짐
    • LIFO 구조라서 스택이라고 불림 (후입선출, Last-In First-Out)
    • JS는 싱글 스레드이므로 하나의 호출 스택을 가짐 (한가지 일task만 처리 가능)
    • 파일이 실행되면 기본적으로 Anonymous라는 가상의 전역 컨텍스트가 생김, 실행이 끝나면 같이 사라짐

 

3. 백그라운드 (Web APIs)

  • 호출 스택에서 비동기 함수가 실행 되면 백그라운드를 호출함
  • 실행을 끝내면 테스크 큐로 보냄
  • 참고로 JS 엔진에 포함된 게 아니라, 브라우저에서 제공하는 API라 비동기 동작이 가능. (DOM, Ajax, Timeout 등이 존재)

 

4. 테스크 큐 (콜백 큐, Callback Queue) 

  • 비동기적으로 실행된 콜백 함수가 보관되는 곳
  • 기본적으로 먼저 들어온 작업이 먼저 실행됨(FIFO, first-in-first-out)
  • 매크로태스크 큐, 마이크로태스크 큐, Animation Frames로 이루어짐.

 

5. 이벤트 루프 (Event Loop)

  • 태스크가 들어오길 기다렸다가 태스크가 들어오면 이를 처리하고, 처리할 태스크가 없는 경우엔 잠드는, 끊임없이 돌아가는 자바스크립트 내 루프
    1. 처리해야 할 태스크가 있는 경우 (+ 호출 스택이 비어있을 때):
      • 먼저 들어온 태스크부터 순차적으로 처리함
    2. 처리해야 할 태스크가 없는 경우:
      • 잠들어 있다가 새로운 태스크가 추가되면 다시 1번으로 돌아감

 

 

function run() {
    console.log('3초 후 실행');
}
console.log('시작');
setTimeout(run, 3000);
console.log('끝');

▲ 호출 스택을 그려 위 코드의 순서 예측해보기

 

※ 전역 컨텍스트를 이해하기 위해선 이 글을 먼저 보자.

 

 

 

 

 

 

function oneMore() {
    console.log('one more');
}
function run() {
    console.log('run run');
    setTimeout(() => {
        console.log('wow');
    }, 0)
    new Promise((resolve) => {
        resolve('hi');
    })
        .then(console.log);
    oneMore();
}

setTimeout(run, 5000);

▲ setTimeout과 Promise로 알아보기.

 

*promise.nestTick -> process.nestTick

▼ 왜 새치기가 생기는 것인가! - 콜백 큐 뜯어보기

 

 

 

그럼 블로킹, 논 블로킹을 비교해 보자

 

▼ 블로킹

function longRunningTask() {
  // 오래 걸리는 작업
  console.log('작업 끝');
}
console.log('시작');
longRunningTask();
console.log('다음 작업');
  • 콘솔 : 시작 → (시간 오래 흐른 후) 작업 끝 → 다음 작업

 

▼ 논 블로킹

function longRunningTask() {
  // 오래 걸리는 작업
  console.log('작업 끝');
}
console.log('시작');
setTimeout(longRunningTask, 0);
console.log('다음 작업');
  • 콘솔 : 시작 → 다음 작업 → 작업 끝

이와 같이 오래 걸리는 작업을 setTimeout()을 사용해 논 블로킹으로 만들어 작업을 효율적으로 할 수 있다

 

※ 실제 노드에서는 setTimeout() 대신 setImmediate()을 주로 사용

 

 

 

 

[참고] 이벤트 루프와 매크로태스크, 마이크로태스크

 

이벤트 루프와 매크로태스크, 마이크로태스크

 

ko.javascript.info

[참고] 마이크로태스크

 

마이크로태스크

 

ko.javascript.info

[참고] 인프런 Node.js 교과서 강의

 

[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지 - 인프런 | 강의

노드가 무엇인지부터, 자바스크립트 최신 문법, 노드의 API, npm, 모듈 시스템, 데이터베이스, 테스팅 등을 배우고 5가지 실전 예제로 프로젝트를 만들어 나갑니다. 최종적으로 클라우드에 서비스

www.inflearn.com

[참고] 어쨌든 이벤트 루프는 무엇입니까? | Philip Roberts | JSConf EU