호출 스택
호출 스택은 함수의 호출을 스택 형식으로 나타낸 것이다. (LIFO 구조라서 스택으로 불린다)
function first() {
second();
console.log('첫 번째');
}
function second() {
third();
console.log('두 번째');
}
function third() {
console.log('세 번째');
}위 코드에 대한 실행 결과는
세 번째
두 번째
첫 번째이다. 이는 호출 스택을 통해 나타낼 수 있다.
-----------------
| third() |
-----------------
-----------------
| second() |
-----------------
-----------------
| first() |
-----------------
-----------------
| anonymous |
-----------------여기서 Anonymous는 가상의 전역 컨텍스트이다.
비동기 함수 호출
그렇다면 비동기 호출 방식 코드를 보겠다.
function run() {
console.log('3초 후 실행');
}
console.log('시작');
setTimeout(run, 3000);
console.log('끝');해당 코드는
시작
끝
3초 후 실행으로 실행된다.
이는 호출 스택 + 이벤트 루프로 설명할 수 있다.
setTimeout(run, 3000); 이 실행된다면 호출 스택에 들어간 후 실행되는데, 비동기함수이기 때문에 백그라운드로 넘어가서 동시에 실행이 된다.
호출 스택 백그라운드
--------------------- -----------------------
| | | |
| | | --------------- |
| | | | 타이머(run, 3초) | |
| --------------- | | --------------- |
| | anonymous | | -----------------------
| --------------- |
---------------------
태스크 큐
------------------------------------------
| |
| |
| |
------------------------------------------백그라운드에서 작업이 끝난다면 태스크 큐로 이동하게 된다.
호출 스택이 비게 된다면, 태스크 큐에 있는 함수가 호출 스택으로 넘어가서 실행이 된다.
호출 스택 백그라운드
--------------------- -----------------------
| | | |
| | | |
| | | |
| | | |
| | -----------------------
| |
---------------------
태스크 큐
------------------------------
| ------- |
| | run | |
| ------- |
------------------------------백그라운드로 가는 대표적인 비동기 함수는 아래와 같다.
- 타이머
- 파일 시스템 작업(I/O)
- 네트워크 요청
- 이벤트 리스너
- 데이터베이스 작업
- 무거운 연산(암호화, 압축)
백그라운드에서는 동기적으로 실행되지 않기 때문에 어떤 함수가 먼저 끝날지는 모른다.
Promise
추가적으로 아래와 같은 코드의 실행 결과는 다음과 같다.
console.log('시작');
setTimeout(() => {
console.log('setTimeout 실행 (매크로태스크)');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 실행 (마이크로태스크)');
});
console.log('끝');시작
끝
Promise 실행 (마이크로태스크)
setTimeout 실행 (매크로태스크)Promise는 우선순위가 높기 때문에 태스크 큐에 먼저 도착하지 않았더라도 가장 먼저 실행이 된다.