[42장] 비동기 프로그래밍

Sheryl Yun·2022년 10월 23일
0
post-thumbnail

실행 컨텍스트

자바스크립트에서 함수를 호출하면 함수를 실행하기 위한 실행 컨텍스트가 생성되어 콜 스택에 추가된다.

콜 스택에 추가된 실행 컨텍스트는 함수가 실행된 후 종료되면 콜 스택에서 팝 되어 제거된다.

코드가 실행되면 콜 스택 맨 아래에는 전역 실행 컨텍스트가 가장 먼저 쌓인다.

이후 함수가 호출되면서 함수 컨텍스트가 그 위에 쌓이고 실행 후 하나씩 제거되는 과정을 반복한다.

동기와 비동기

자바스크립트 엔진은 단 하나의 실행 컨텍스트 스택(= 콜 스택)을 갖는다.

이는 함수를 실행할 수 있는 장치가 하나뿐인 것을 의미한다.

따라서 자바스크립트 엔진의 기본 동작은 한 번에 하나의 태스크만 실행할 수 있는 싱글 스레드이다.

🧘‍♀️ 동기

콜 스택에 쌓이는 순서대로 함수가 처리된다. 동시에 여러 개의 함수를 실행할 수는 없어 이전 함수 실행이 끝날 때까지 다음 함수 실행이 중단된다.

  1. 처리 순서가 보장된다.
  2. 블로킹(blocking) 현상이 발생한다.

🏃‍♀️ 비동기

한 번에 여러 개의 태스크를 실행할 수 있다. 브라우저 환경의 여러 장치의 도움을 받아 가능하다.

  1. 동기 방식에서의 블로킹 현상이 발생하지 않는다.
  2. 함수의 처리 순서가 보장되지 않는다.

이벤트 루프와 태스크 큐

자바스크립트는 브라우저 환경에서 더 많은 태스크를 비동기적으로 처리할 수 있다.

[ 자바스크립트가 비동기로 실행되어야 하는 경우의 예시 ]
1. HTML 요소에 애니메이션 효과를 넣을 때
2. 서버에 HTTP 요청 후 응답 데이터를 화면에 렌더링할 때

비동기를 가능하게 하는 브라우저 환경

브라우저에는 자바스크립트를 구동시키기 위한 자바스크립트 엔진과,
브라우저 자체 내장 장치인 Web API,
실행할 함수들을 대기시키는 태스크 큐,
태스크 큐에서 콜 스택으로 옮기는 이벤트 루프라는 메커니즘이 있다.

[ 브라우저 Web API 종류 ]
1. DOM API (이벤트 핸들러 등)
2. 타이머 함수 (setTimeout, setInterval 등)
3. HTTP Request (fetch, axios 등)

자바스크립트 엔진

콜 스택으로 구성된다.
단순히 콜 스택에서 실행할 함수를 받아 처리하는 역할만 담당한다.

'객체'가 저장되는 메모리 공간이다.
콜 스택 안에 쌓인 실행 컨텍스트가 실행될 때 힙에 저장된 객체를 참조한다.

객체는 원시 값과 달리, 값을 저장할 메모리의 크기가 정해져 있지 않다. 따라서 객체를 저장하는 힙은 '구조화되어 있지 않다'.

🥞 콜 스택

스택(Stack) 구조이다. 즉, 나중에 들어간 것이 가장 먼저 나오는 LIFO(Last In First Out) 구조이다.

코드 실행이 시작되면 자바스크립트는 코드를 스캔(평가)하고, 실행할 함수들을 태스크 큐에서 일시 대기시켰다가 태스크 큐에 가장 먼저 들어온 함수부터 차례로 콜 스택으로 이동시킨다.

태스크 큐는 자료 구조 중 큐(Queue)에 해당한다. 즉, 먼저 들어간 것이 먼저 나오는 FIFO(First In First Out) 구조이다.

🍢 태스크 큐

비동기 로직이 콜 스택으로 이동하기 전 일시적으로 보관되는 영역이다.

일반적인 태스크 큐는 매크로 태스트 큐이다.

이와는 별개로 Promise의 후속 처리 메서드의 콜백 함수가 보관되는 마이크로 태스크 큐가 있다.

실행 순서는 마이크로 태스크 큐가 우선한다.

🧲 이벤트 루프

태스크 큐에서 콜 스택으로 실행할 함수들을 옮겨주는 브라우저 환경 내의 '보이지 않는 손'이다.

[ 이벤트 루프가 태스크 큐에 대기 중인 함수를 콜 스택으로 이동시키는 조건 2가지 ]

  1. 태스크 큐에 대기 중인 비동기 로직이 있을 때
  2. 동기 코드가 모두 실행되어 콜 스택이 비어있을 때

타이머가 0초인 비동기 함수는 바로 실행될까?

function foo() { console.log('foo'); }

function bar() { console.log('bar'); }

setTimeout(foo, 0); // 0초(실제로는 4ms) 후에 foo 함수 호출

bar();

답: 아니다.

타이머 함수의 지연 시간(delay)이 4ms 이하인 경우 최소 지연 시간 4ms가 지정된다.

따라서 타이머의 시간이 0초일지라도 실제로는 4ms 이후에 콜백 함수 foo가 태스크 큐에 들어가게 된다.

주의 🐡
타이머의 시간은 '콜백 함수가 태스크 큐에 들어갈 시점'을 결정한다. 이후 태스크 큐에서 콜 스택으로 언제 이동되어 실행되는지는 보장하지 않는다. 콜백 함수가 태스크 큐에서 콜 스택으로 이동하려면, 이벤트 루프의 '콜 스택이 비어있어야 한다'는 조건까지 충족해야 하기 때문이다.

profile
데이터 분석가 준비 중입니다 (티스토리에 기록: https://cherylog.tistory.com/)

0개의 댓글