오늘 정리하고자 하는 주제는 브라우저의 동작원리이다.
내가 작성한 코드들이 어떻게 돌아가는지 알아야 코드도 잘 짤 수 있다고 생각이 들었기에 브라우저의 동작원리를 살펴볼 것이다.
🚀 V8 엔진
브라우저마다 쓰이는 엔진의 종류는 다르지만 내가 쓰는 크롬의 v8엔진의 구조이다.
이 구조는 인터넷에서도 많이 봤을 거라 생각이 들지만 설명을 해보자면,
✔️ Memory Heap :
메모리 할당이 일어나는 곳
✔️ Heap :
구조화되지 않은 넓은 메모리 영역 => 객체(변수, 함수 등)들이 담김
✔️ Call Stack:
실행될 코드의 한 줄 단위로 할당되는 곳
✔️ Web APIs:
비동기 처리를 담당하는 곳
✔️ Callback Queue:
비동기 처리가 끝난 후 실행되어야 할 콜백 함수가 차례로 할당되는 곳
✔️ Event Loop:
Queue에 할당된 함수를 순서에 맞춰 Call Stack에 할당해주는 역할
각각 이런 역할들을 하고 있다.
그럼 이제 코드를 보면서 살펴보자.
1. 동기적 코드
코드 안에 비동기 코드가 없다면 WEb APIs가 필요 없이 Call Stack만으로도 동작이 가능하다.
왼쪽과 같은 코드가 있을 때 Call Stack이 어떤 식으로 처리가 되는지 확인해보자.
1. 코드가 실행될 때 코드 전체를 가지고 있는 anonymous가 담김
2. first 함수 호출
3. second 함수 호출
4. third 함수 호출
5. console.log("빨리요")
이 순으로 콜 스택에 담기게 되고 차례대로 위에서부터 실행이 된다.
그리고 차례대로 함수가 실행되면서 내부에 있는 console.log들이 실행이 되고 모두 다 종료가 되면
최종적으로 anonymous가 콜 스택에서 사라지는 구조이다.
따라서 콘솔 창에는
"빨리요"
"국밥 한 그릇 주세요"
"저기요"
"빨리요"
이렇게 확인할 수 있다.
그렇다면 이벤트 루프의 핵심이 비동기 코드를 살펴보자.
2. 비동기적 코드
대표적인 비동기 함수인 setTimeout 함수이다. 윗 코드는 어떻게 동작될까?
자바스크립트를 조금 다뤄본 사람이라면 손쉽게
"저기요"
"빨리요"
"국밥 한 그릇 주세요"

콜 스택에 setTimeout함수가 들어오니 실행하지 않고 일단 Web APIs로 보낸다.
그리고 나머지 코드를 실행하고
이벤트 루프가 콜 스택이 비어있는 것을 확인한 뒤
setTimeout 함수를 콜 스택에 올리고 코드가 종료된다.
여기서 중요한 것은 콜 스택이 비어있다는 것이다.
콜 스택이 비어있기 때문에 익명 함수를 콜 스택에 넣을 수 있는 것이고, 이게 이벤트 루프가 하는 역할이다.
코드를 보면 어떻게 실행이 되는지 예상하는 것은 쉽지만,
막상 내부에서 이렇게 동작하고 있다는 것을 알게 되니 복잡하다는 것을 알게 됐다.
또한 앞으로는 어떤 코드를 만나더라도 이런 식으로 돌아가겠구나라고 이해할 수 있는 계기였다.
이렇게 비동기 함수가 처리되는 것을 확인하고 나니 그럼 비동기 함수가 여러 개일 경우에는 어떻게 처리될까?
라는 생각이 들었고 바로 실행해봤다.
3. 비동기 함수가 여러 개라면 어떻게 실행될까
콘솔 순서는 1. 시작 2. 끝났어 까지는 알겠지만 setTimeout과 Promise순서는 어떻게 될지 예상이 안됐다.
결과적으로는
"시작"
"끝났슈"
"Promiseset"
"Timeout"
이렇게 콘솔에 확인이 됐고, 내가 깨달았던 것은 Call Stack에도 우선순위가 있구나!라는 것이다.
그럼 결과는 이렇게 나온 것을 확인했고 내부적으로 어떻게 굴러가는지 확인해보자.
브라우저 내부에서는 이렇게 동작하고 있었는데
Callback Queue에 쌓이는 순서는 상관없다는 것을 알게 됐고, 이 안에서의 우선순위가 어떻게 되는지 찾아봤다.
4. Callback Queue
콜백 큐의 내부를 까 보면 이런 식으로 나뉘어 있다.
정리해보자면, 어떤 콜백 함수인지 판단하여 Task Queue, Microtask Queue, Animation Frames 안에 넣고,
이것의 우선순위에 따라 콜 스택으로 올라간다는 것이다.
각 우선순위는
Microtask Queue > Animation Frames > Task Queue
이렇게 되며 Microtask Queue 안에 Promise 가 있고 Task Queue 안에 setTimeout 이 있었기에 이러한 순서로 동작되는 것이었다.
👏 마치며
브라우저의 동작원리를 이해함으로써 오래 걸리는 코드는 비동기 함수로 처리하면 좋을 것 같다고 생각했고,
코드를 짤 때 브라우저의 동작원리를 생각하며 짜야겠다고 느꼈다.
또한 여태 내가 마주했던 비동기의 오류의 원인을 알게 되었다.
참조
https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif
'JavaScript' 카테고리의 다른 글
[JavaScript] 제너레이터와 async/await (0) | 2023.01.05 |
---|---|
[JavaScript] Event Flow ooO (1) | 2022.12.24 |
[JavaScript] this에 관한 탐구 (0) | 2022.12.03 |
[JavaScript] 클로저를 이해하기 위한 여정 (0) | 2022.11.25 |
[JavaScript] 프로토타입 (prototype) (0) | 2022.06.29 |