자바스크립트에서 함수를 호출하면 함수를 실행하기 위한 실행 컨텍스트가 생성되어 콜 스택에 추가된다.
콜 스택에 추가된 실행 컨텍스트는 함수가 실행된 후 종료되면 콜 스택에서 팝 되어 제거된다.
코드가 실행되면 콜 스택 맨 아래에는 전역 실행 컨텍스트가 가장 먼저 쌓인다.
이후 함수가 호출되면서 함수 컨텍스트가 그 위에 쌓이고 실행 후 하나씩 제거되는 과정을 반복한다.
자바스크립트 엔진은 단 하나의 실행 컨텍스트 스택(= 콜 스택)을 갖는다.
이는 함수를 실행할 수 있는 장치가 하나뿐인 것을 의미한다.
따라서 자바스크립트 엔진의 기본 동작은 한 번에 하나의 태스크만 실행할 수 있는 싱글 스레드이다.
콜 스택에 쌓이는 순서대로 함수가 처리된다. 동시에 여러 개의 함수를 실행할 수는 없어 이전 함수 실행이 끝날 때까지 다음 함수 실행이 중단된다.
한 번에 여러 개의 태스크를 실행할 수 있다. 브라우저 환경의 여러 장치의 도움을 받아 가능하다.
자바스크립트는 브라우저 환경에서 더 많은 태스크를 비동기적으로 처리할 수 있다.
[ 자바스크립트가 비동기로 실행되어야 하는 경우의 예시 ]
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가지 ]
function foo() { console.log('foo'); }
function bar() { console.log('bar'); }
setTimeout(foo, 0); // 0초(실제로는 4ms) 후에 foo 함수 호출
bar();
답: 아니다.
타이머 함수의 지연 시간(delay)이 4ms 이하인 경우 최소 지연 시간 4ms가 지정된다.
따라서 타이머의 시간이 0초일지라도 실제로는 4ms 이후에 콜백 함수 foo가 태스크 큐에 들어가게 된다.
주의 🐡
타이머의 시간은 '콜백 함수가 태스크 큐에 들어갈 시점'을 결정한다. 이후 태스크 큐에서 콜 스택으로 언제 이동되어 실행되는지는 보장하지 않는다. 콜백 함수가 태스크 큐에서 콜 스택으로 이동하려면, 이벤트 루프의 '콜 스택이 비어있어야 한다'는 조건까지 충족해야 하기 때문이다.