Javascript 의 런타임 모델은 코드의 실행, 이벤트의 수집과 처리, 큐에 대기 중인 하위 작업을 처리하는 이벤트 루프에 기반하고 있으며, C또는 Java 등 다른 언어가 가진 모델과는 상당히 다릅니다.
웹 브라우저 동작원리를 알아야하는 이유
-> 저희가 짠 코드는 크롬에서 실행되기 때문입니다!
동작원리 예시 코드
console.log(1+1)
setTimeout(function(){console.log(2+2}},1000) // 1초뒤에 실행
console.log(3+3)
console이 어떻게 찍히는지 다들 아시나요?
2
6
1초뒤에 4
이렇게 나오겠죠? 마치 병렬처리 같지만 아닙니다!
**참고
Heap에는 변수로 사용되는 객체(변수, 함수등)이 저장되서 stack에서 찾아서 사용하게 됩니다.
동작원리를 이해쉽게 하려면 유투브에 검색해서 잘 만들어진 조교들의 동영상을 보면 확실히 잘 이해가 됩니다.
처음 스택에 저희가 짠 코드들이 올라가고 그것을 한줄 한줄 읽게 됩니다.
이렇게 말이죠.
1+1이 실행되고 나서 2+2를 실행하려고 보니 1초뒤에 실행해라!라는 명령이 있기 때문에 저 코드는 대기실(Web APIs -> QUEUE)로 이동했다가 1초뒤에 실행이 되게 만듭니다.
그 다음 2+2를 대기실로 보내고 3+3이 출력이되고 1초뒤 2+2가 실행이 되는 것이죠.
대기실에 들어가는 코드들은 Ajax 요청코드, 이벤트리스너, setTimeout 등이 있습니다.
하지만 QUEUE에 들어간 코드들은 stack이 비었을 때 들어가는 약속이 있습니다. 따라서 코드가 엄청나게 많으면 1초뒤가 아니라 더 많은 시간이 지난 다음에 2+2가 출력이 될 수도 있습니다.
그렇다면 setTimeout에 대기시간을 0초로 하면 콘솔이 순서대로 찍힐까요?
이것도 당연히 아닙니다. 아까 위에서 말했듯이 대기실에 들어가는 코드들은 묻지도 따지지도 않고 대기실에 들어가서 줄을 섭니다.
서버를 빠르게 만드려면 stack이나 queue를 바쁘게 만들면 안됩니다.
이것에 대해 공부를 하다보니 제가 매번 쓰던 비동기 함수들에 대해서도 궁금함이 생기더라고요.
async, await 를 통해 함수 실행에 순서를 매기는 방법이 있어서 개인적으로 생각을 해본 것인데,
async 속에 await를 사용해서 함수 실행 시 지금 실행한 함수를 먼저 실행하고 다음 stack으로 넘어가라! 가 되는 것이고 이 함수가 실행이 되지 않으면 다음 함수를 실행할 수 없게 되는 것이 라고 생각이 됩니다.
크롤링 관련 프로그래밍을 제작할 때도 비동기 함수를 사용해서 순서대로 크롤링한 후 DB에 데이터를 저장했는데, 비동기를 사용하지 않고 진행했을 때 DB에 저장되는 값이 뒤죽박죽으로 저장되더라고요.
이러한 웹 브라우저의 동작원리를 깊게 알게 된다면, 서버의 속도를 빠르게 할 수 있고 동작도 자유자재로 할 수 있다고 생각이 됩니다. 다음에 기회가 되면 더 알아보도록 하겠습니다.
추가 내용
function first(){
second()
console.log(1)
}
function second(){
third()
console.log(2)
}
function third(){
console.log(3)
}
first()
third()
이것에 대한 정답이 뭐라고 생각되시나요?
네 맞습니다. 3 2 1 3 이 맞습니다.
Call Stack에 익명함수(anonymous function)이 먼저 들어가고
→ first() → second() → third() → console.log(3)
이렇게 stack이 쌓이고 하나하나 함수가 실행이 됩니다. 처음에 봤을 때 신기하더라고요 .... 이런것도 모르고 코드를 짰다니 ㅎㅎ 이제라도 알았으니 다행입니다.
call stack이 많이 쌓이면 에러가 나는데 크롬은 약 12만개? 정도 쌓이면 에러가 난다고 하네요.
추가추가 내용
console.log('시작');
setTimeout(function () {
console.log('중간');
}, 0);
Promise.resolve().then(function () {
console.log('promise');
});
console.log('끝');
이것은 어떻게 동작하는지 아시겠나요?
정답은 시작 끝 promise 중간 입니다.
왜 그럴까요??
이유는 Web API 에서 QUEUE로 넘어갈 때 Task Queue , Microtask Queue, Animation Frames 이런 형태로 넘겨지게 됩니다.
Queue에서 stack으로 넘어가는 순서는
Microtask Queue > Animation Frames > Task Queue
이렇게 됩니다.
- Microtask Queue
- PromiseJobs 라는 internal queue
- V8엔진에서는 이것을 Microtask queue 라고 부릅니다.
- Task Queue
- setTimeout(), setInterval(), setImmediate() 와 같은 task를 넘겨받습니다.
- Animation Frames
- requestAnimationFrame : 브라우저에게 수행하기를 원하는 애니메이션을 알리고 다음 리페인트가 진행되기 전에 해당 애니메이션을 업데이트하는 함수를 호출하게 합니다.
출처
https://developer.mozilla.org/ko/docs/Web/JavaScript/EventLoop
https://www.youtube.com/watch?v=v67LloZ1ieI
https://developer.mozilla.org/ko/docs/Web/API/Window/requestAnimationFrame