- 이벤트 루프
- 태스크 큐
- 잡 큐 / 마이크로 태스크 큐
즉, 싱글 스레드로 동작하기 때문에 한 번에 하나의 태스크만 처리할 수 있다는 것이다.
그치만 자바스크립트는 동시성을 지원하는 이벤트 루프 가 브라우저에 내장되어 있어 비동기 처리를 구현해낼 수 있다.
메인 스레드의 콜 스택(Call stack - execution context stack) 은 비동기 환경인 태스크 큐(Task queue) 와 잡 큐(Job queue) 로 부터 비동기 코드의 호출, 반환을 처리한다.
이 과정에서 모든 코드가 실행되어 콜스택이 비워지면 이벤트 루프를 체크하면서 태스크 큐에 태스크가 남아있는지 확인한 후 콜스택으로 가져와서 처리할 수 있다.
이 과정에서
만약 콜 스택이 비어 있고 태스크 큐에 대기중인 함수가 있다면 이벤트 루프는 순차적으로 태스크 큐에 대기중인 함수를 콜 스택으로 이동시킨다.
(자바스크립트 엔진은 콜 스택이 비워지면, 태스크 큐의 콜백 함수를 실행한다.)
function greeting () {
console.log('Hey');
}
function closing () {
console.log('See you');
}
setTimeout(greeting, 0);
closing();
// 1. 실행 컨텍스트 생성, 콜 스택에 푸시
// 2. setTimeout 함수 호출 > 실행 > 콜 스택에서 pop > 태스크 큐에 push
// 3. 이벤트 루프에 의해 콜 스택이 비어있음을 확인 > 태스크 큐에 대기중인 greeting이 콜 스택에 push
// 4. 콘솔창 : See you
// Hey
태스크 큐는 이벤트 큐( event queue ), 콜백 큐( callback queue) 로도 불리며 setTimeout, setInterval 과 같은 비동기 함수의 콜백 함수, 이벤트 핸들러가 일시적으로 보관되는 영역이다.
자바스크립트는 비동기 처리를 위한 패턴으로 Promise를 도입했다.
Promise API에서는 태스크 큐가 아닌 잡 큐, 마이크로 태스크 큐를 사용하는데 둘 다 태스크 큐 보다 우선순위가 높다.
setTimeout( () => {
console.log("타임아웃 1")
}, 0);
Promise.resolve().then( () => console.log("프로미스 1"));
setTimeout( () => {
console.log("타임아웃 2")
}, 0);
Promise.resolve().then( () => console.log("프로미스 2"));
// 실행결과 : 프로미스 1 > 프로미스 2 > 타임아웃 1 > 타임아웃 2
잡 큐( job queue )와 마이크로태스크 큐( microtask queue )는 비동기 API 중 하나인 Promise API에서 사용되며 마이크로태스크 큐 > 잡 큐 > 태스크 큐 순서로 우선순위를 가진다.
마이크로태스크 큐는 Promise의 콜백 함수들이 실행되는 장소로 then(), catch(), finally() 와 같은 메소드들이 호출되는 비동기 작업이 완료된 직후에 해당 작업의 콜백 함수가 등록된다.
또한, 마이크로태스크 큐는 현재 실행중인 태스크가 완료되면 즉시 실행되며 Promise.resolve(), Promise.reject() 로 생성된 promise에 해당하는 콜백을 등록할 수있다.
잡 큐는 주로 비동기 함수의 콜백 함수가 등록되는 곳으로 setTimeout 또는 setInterval과 같은 비동기 함수의 콜백 함수가 등록되고 처리된다.
console.log("start");
// Promise
Promise.resolve().then(() => console.log("micro 1"));
Promise.resolve().tehn(() => console.log("micro 2"));
// setTimeout
setTimeout(()=> console.log("job 1"), 0);
setTimeout(()=> console.log("job 2"), 0);
console.log("end");
// 출력결과
// start
// end
// micro 1
// micro 2
// job 1
// job 2