기술면접을 준비하면서 공부했던 내용들을 정리하고자 오랜만에 블로그에 들어왔습니다.
이번 글에서는 자바스크립트 동작에 대해서 글을 적어보려고 합니다.
1. JavaScript
이전에 자바스크립트에서 작성한 글이 있지만 해당 글을 이해하기 위해서 간단하게 알고 넘어가야하는 개념이 있습니다.
자바스크립트는 싱글 스레드 언어입니다. 따라서 명령어 여러개를 동시에 처리하는 것이 아니라 한줄씩 처리할 수 있습니다.
2. JavaScript 구성
자바스크립트 동작을 이해하려면 자바스크립트 엔진, Web API, queue, Event Loop으로 구성되어 있습니다.
2-1. 자바스크립트 엔진
자바스크립트 엔진에는 heap과 stack이 있습니다. heap에는 원시타입, 객체타입이 선언이 되면 메모리 힙에 할당이 되고, 사용이 끝나면 자동으로 힙에서 해제됩니다. stack은 실행해야하는 코드인 실행 컨텍스트가 쌓입니다. 코드 실행시 push, 실행이 끝나면 pop이 됩니다.
여기에서 실행 컨텍스트란 실행가능한 코드가 실행되기 위해서 필요한 환경을 모아놓은 객체입니다. 기본적으로는 글로벌 컨텍스트가 스택 가장 아래 쌓이고 그 다음으로 함수 컨텍스트 들이 위로 차례로 쌓입니다.
2-2. Web API
Web API에는 Ajax 요청, SetTimeout, setInterval, 이벤트 핸들러의 등록과 같은 웹 브라우저에서 제공하는 기능들입니다. 해당 기능들은 그립과 같이 자바스크립트 엔진과는 떨어져 있는 것을 확인할 수 있습니다.
2-3. Queue
다음으로는 Queue 입니다. Queue라고 하면 선입선출, 먼저 들어온 객체가 먼저 나가는 자료구조입니다. 그림에는 Callback queue만 있는데 사실은 Callback queue를 포함해서 MicroTask queue, Animation Frame이 추가로 해서 3개의 queue가 있습니다.
우선 Callback queue는 MacroTask queue 또는 Task queue라고도 불립니다. 해당 queue는 Ajax, setTimeOut, setInterval, setImmediate와 같은 task의 결과를 넘겨 받습니다. 우선순위는 3개의 queue중에서 가장 낮습니다.
다음으로는 MicroTask queue입니다. 해당 queue는 promise, async/await, process.nextTick 과 같은 비동기 호출을 넘겨 받습니다. 3개의 queue중에서 우선순위가 가장 높습니다.
다음으로는 AnimationFrame입니다. requestAnimationFrame과 같은 브라우저 렌더링과 관련된 task를 넘겨받습니다. 3개의 queue중에서 우선순위가 2번째로 높습니다.
정리해보면 queue는 총 3개가 있으며 우선순위는 MicroTask queue > AnimationFrame > MacroTask queue 입니다.
이해가 잘 안되신다면 아래 블로그 글을 참고하시면 좋을거 같습니다!
2-4. Event Loop
Event Loop은 Stack이 비어져 있으면 Queue에서 대기중인 작업을 Stack으로 올려줍니다.
3. 동작
간단한 개념들을 익혔으니 이제는 동작을 알아보겠습니다.
console.log("start")
setTimeout(function() {
console.log("setTimeout")
}, 0)
promise.resolve()
.then(functuon() {
console.log("promise")
})
console.log("end")
여러분들은 이 코드의 결과가 어떻게 나올거 같으신가요? 정답은 아래와 같이 나옵니다.
start
end
promise
setTimeout
1. 우선 Stack 가장 아래에는 글로벌 컨텍스트가 쌓입니다.
2. console.log("start")가 Stack에 push되고 실행이 될 것입니다. 실행이 되면 Stack에서 pop됩니다.
3. 그 다음 실행인 setTimeOut()이 Stack에 쌓입니다. 이제 setTimeOut이 실행이되야하는데 위에서 setTimeout은 Web API 중 하나입니다. 따라서 순서가 이전 console.log()랑 다릅니다. 우선 Stack에서 pop이 되고난 다음 Web API setTimeout에게 실행하라고 신호를 보냅니다. 그러면 Web API에서 setTimeout을 실행시킵니다. setTimeout이 자바스크립트 엔진이 아닌 Web API에서 실행이 되면서 Stack에는 promise.resolve()가 스택에 push되는 것입니다. 이렇게 비동기 처리가 싱글스레드에서 일어나는 것입니다.
setTimeout의 실행이 끝나면 결과인 console.log("setTimeout")은 MacroTask queue에 들어가게 됩니다.
4. 이 과정이 일어나면서 Stack에서는 promise.resolve()를 실행 시킵니다. Stack에서 pop이되고 결과인 then()이 MicroTask queue에 들어가게 됩니다.
5. 마지막으로 console.log("end")가 Stack에 push되고 실행이 된 다음 Stack에서 pop됩니다.
6. 이제 더이상 실행할 코드가 없기 때문에 글로벌 컨텍스트가 pop되고 Stack은 비워집니다.
여기까지보면 console 창에는 start, end 만 적혀 있습니다
7. 이제 Event Loop가 Stack이 비워져 있는 것을 확인하고 Queue를 확인합니다. 우선 MicroTask queue에 있는 promise.resolve() 결과인 then()을 Stack에 Push시킨 뒤 코드를 실행하여 console에 promise가 추가됩니다. 그 다음 Stack에서는 pop됩니다.
8. AnimationFrame에는 아무 것도 없고 마지막으로 MacroTask queue에 있는 setTimeout() 결과를 Stack에 Push하고 실행시킨 뒤 pop합니다.
이렇게 모든 코드가 동작했습니다.
뭔가 말로 적어서 조금 난잡하긴 한데, Queue에서 링크 걸어드린 블로그를 참고하시면 많은 도움이 되실거 같습니다.
'언어 > JavaScript' 카테고리의 다른 글
JavaScript와 Node.js (1) | 2020.11.21 |
---|