April 13, 2022
자바스크립트는 싱글 스레드 언어이다. 싱글 스레드의 의미는 작업을 하나씩만 수행할 수 있고 다수의 작업을 동시에 수행하는 것은 불가능하다는 것을 말한다. 하지만 브라우저가 동작하는 것을 살펴보면 많은 작업들이 동시에 실행되는 것처럼 보인다. 이를 가능하게 해주는 것이 이벤트 루프(Event Loop)이며 이벤트 루프는 자바스크립트에게 동시성을 지원해준다.
하지만 여기서 확실히 짚고가야할 부분은 이벤트 루프가 ECMAScript에 명세되어 있는 개념이 아니라는 것이다. 즉, 이벤트 루프는 자바스크립트를 구동하는 환경인 브라우저나 Node.js에서 제공하는 다양한 기능 중 하나이다.
위 그림은 이벤트 루프를 설명하기 위해서 필요한 브라우저 내부의 요소들이고 자세한 내용은 다음과 같다.
자바스크립트 엔진
Web APIs
콜백 큐(테스크 큐)
push
되는 큐(Queue)이다.기본적인 동작 과정은 다음과 같다.
push
push
push
된 작업을 실행하고 완료된 후에 전체 작업 종료여기서 알 수 있듯이 이벤트 루프의 역할은 콜 스택과 테스크 큐를 항상 바라보고 있다가 콜 스택이 비어 있으면 테스크 큐에서 대기하고 있는 콜백을 콜 스택으로 이동시켜주는 것이 전부이다.
위에서는 태스크 큐가 하나인 것처럼 동작 과정을 설명했지만 사실 태스크 큐는 다음과 같이 2가지 종류로 나누어진다.
매크로태스크 큐(Macrotask Queue)
마이크로태스크 큐(Microtask Queue)
여기서 중요한 점은 마이크로태스크 큐가 매크로태스크 큐보다 우선순위가 높다는 것이다.
이제 브라우저가 비동기를 제어하는 과정과 이벤트 루프의 역할도 알아보았다. 그리고 태스크 큐도 매크로태스크 큐와 마이크로태스크 큐로 나눠진다는 사실을 확인했으니 마지막으로 다음 예시의 동작을 분석해보고 확실하게 정리해보자.
console.log('start')
setTimeout(function() {
console.log('setTimeout')
}, 0)
Promise.resolve()
.then(function() {
console.log('promise1')
})
.then(function() {
console.log('promise2')
})
const deley = () => {
for (let i = 0; i < 100000; i++) {
for (let j = 0; j < 100000; j++) {}
}
}
deley()
console.log('end')
start
end
promise1
promise2
setTimeout
위 예시 코드의 동작 과정은 다음과 같다.
start
를 출력 (console
의 실행 과정은 생략)setTimeout
을 백그라운드로 이동then
함수가 백그라운드로 이동 (Promise는 then
, catch
이전까지는 동기적으로 동작)setTimeout
과 2개의 then
함수의 실행이 완료setTimeout
의 콜백이 매크로태스크 큐로 push
되고 대기then
의 콜백이 마이크로태스크 큐로 push
되고 대기end
를 출력한다.promise1
과 promise2
를 출력setTimeout
을 출력