해당 포스트에서는 이벤트 루프의 microtask와 macrotask에 대해 소개하고 이벤트루프가 어떻게 tasks를 처리하는지에 대해서 소개해주고 있다.
자바스크립트는 싱글 스레드 프로그래밍 언어이지만 이벤트 루프를 사용하여 동시성을 지원하기 때문에 여러 작업이 동시에 진행되는 것처럼 느낄 수 있다.
이벤트루프내에는 실제로 2가지 타입의 queue가 존재하는데 우리가 지금까지 불러왔던 task Queue인 (macro)task queue와 microtask queue가 존재한다.
(지금까지는 하나의 task queue만 존재하는 줄 알았다...)
Microtask는 주로 아래의 목록들을 사용한 함수나 프로그램이 종료된 후 call stack이 비어져있을 때 실행되는 짧은 함수이다.
Promise callback
queueMicrotask
Macrotask는 이벤트 루프의 stack이나 microtask가 비어져있을 때 실행되는 짧은 함수이다.
setTimeout
setInterval
setImmediate
Promise가 resovle되고 then(), catch() 또는 finally() 메서드를 호출되었을 때, 메서드 내에 있는 콜백은 Microtask queue에 들어가게 된다. 즉, 메서드 내의 콜백은 즉시 실행되지 않고 기본적으로 비동기 동작에 더해지게 된다.
그렇다면 콜백은 언제 실행될지가 궁금할 것이다.
이벤트 루프는 task들에 대해서 다르게 우선순위를 부여한다.
현재 call stack에 있는 모든 함수들은 실행되고 값을 반환하게 되면 그 함수는 stack에서 빠져나가게 된다.
call stack이 비어졌을 때, 모든 대기중인 microtask들은 call stack에 하나씩 꺼내지며 실행된다.
만약 call stack과 microtask queue 모두 비어졌을 때, 이벤트 루프가 (macro)task queue를 확인하고 남아있는 task queue를 call stack에서 꺼내지며 실행된다.
이제 실제 코드로 살펴보겠다.
이 코드에는 macro task(setTimeout) 그리고 microtask(Promise then() callback)이 있다. 엔진이 SetTimeout 함수에 도달하게되면, 코드를 단계별로 실행하고 무엇이 기록되는지 보겠다.
첫번째 줄에 엔진은 console.log()
메서드를 만나게 된다. 이것은 call stack에 더해지게 되고 이후에 콘솔에는 Start!가 찍히게 된다. 메서드가 call stack에서 제거되고 엔진은 계속 코드를 읽어간다.
엔진은 setTimeout
메서드를 만나게되고 call stack에 꺼내지게 된다. setTimeout
메서드는 브라우저에 고유하기 때문에 콜백함수인 (() => console.log('Timeout!')
은 타이머가 완료될때까지 Web API에 더해지게 된다. 비록 타이머가 0
으로 셋팅되었지만 콜백함수는 우선 Web API에 더해지고 그 다음에 macro(task) queue
에 더해지게 된다.
이제 엔진은 Promise.resolve()
메서드를 만나게 된다. 해당 메서드는 call stack에 더해지게 된다. 그리고 이후에 Promise!
값으로 resolve되며 then()
메서드의 콜백함수는 microtask queue
에 더해지게 된다.
엔진은 console.log()
메서드를 만난다. 즉시 call stack에 추가된 후 콘솔에 End!를 기록하고 call stack에서 꺼내지며 엔진은 계속 코드를 읽는다.
엔진은 이제 call stack이 비어져있음을 확인한다.
call stack이 비어져있기 때문에 microtask queue에 대기중인 task가 존재하는지 체크하게되고 then()
콜백함수가 존재하기 때문에 call stack에서 꺼내지게 된다. 그러면서 Promise의 resovle 값인 Promise!
가 기록되게 된다.
엔진은 다시 call stack이 비어져있음을 보게되고 microtask queue에 다시한번더 대기중인 task가 있는지 체크하게 된다.
이제는 microqueue에는 대기중인 task가 없기 때문에 (macro)task queue를 체크해볼 차례이다.
setTimeout
콜백이 여전히 기다리고 있기 때문에 setTimeout
콜백은 callstack에 더해지게 된다. 콜백 함수는 In timeout!
이라는 기록을 남기는 console.log()
메서드를 반환한다. setTimeout
은 이제 call stack에서 빠져나게된다.
마침내 모든것이 완료되었다.🥳 이제는 자바스크립트 비동기로 작업할 때 발생할 수 있는 "예기치 않은" 혹은 "예측할 수 없는" 동작이 이제 좀 더 이해가 되었으면 한다!