<ABOUT 자바스크립트의 데이터 처리 과정 feat이벤트 루프5탄>

강민수·2021년 12월 11일
0

백엔드

목록 보기
5/21

드디어~ 여기까지 온건가.....

길고 길었던 동기와 비동기에서 자바스크립트가 웹에서 데이터를 처리하는 과정까지 왔다.

그 첫 시작으로 우리는 이벤트 루프와 관련된 용어를 익혀야만 한다.

자 이제 숲을 보자~

이 그림을 이제 하나 씩 구조 분해를 하면서 이벤트 루프가 돌아가는 과정을 익혀야만 우리가 여태 배운 내용들이 머릿 속에 하나, 둘 정리가 될 것이다.

<1. preview>

JS Engine

크게 자바스크립트 엔진은 Memory Heap 과 Call Stack 으로 구성되어 있다.(그림 왼쪽!)
가장 유명한 것이 구글의 V8 Engine이다.
자바스크립트는 단일 스레드 (sigle thread) 프로그래밍 언어인데,
이 의미는 Call Stack이 하나 라는 이야기이다.
(멀티가 되지 않고, 하나씩 하나씩 처리한다는 의미!)
-> 그래서 동기 비동기때 얘기한 구조가 이 말이다. 원래 자바스크립트가 동기적인 구조라는 것이 콜 스텍이라는 작업 공간이 하나 뿐이라서 여기서만 작업이 가능한다는 소리다. 그런데 우리가 편의상 그 작업 공간에서 비동기 방식으로 처리하는 것일 뿐이다.

Memory Heap : 메모리 할당이 일어나는 곳

heap: 구조화 되지 않은 넓은 메모리 영역.
-> 대개 이 부분에는 우리가 프로그램에서 선언한 변수나, 함수 등이 담겨져 있다.

Call Stack(호출 스택) : 코드가 실행될 때 쌓이는 곳. stack 형태로 쌓임.

실행될 코드의 한 줄 단위로 할당되는 자료 구조. 자바스크립트는 인터프리터로 동작을 하기때문에, 한 줄 단위로 코드를 실행하고 해석하게 된다. 그 한 줄 단위가 콜 스택에 담긴다.
Stack(스택) : 자료구조 중 하나, 선입후출(LIFO, Last In First Out)의 룰을 따른다.

Web API(노드에서는 백그라운드로 설명)

그림의 오른쪽에 있는 Wep API는 js 엔진 밖에 그려져 있는데, 다른 건 아니고 그냥 쉽게 생각해서 저렇게 js 엔진 밖에서 비동기를 처리해 주는 구조라고 보면 된다.

Callback Queue(Task Queue, Event Queue 등 다양한 형태로 설명)

콜백 큐 안에 테스크 큐 같은 것들이 있는 것이다.
비동기적으로 실행된 콜백함수가 보관 되는 영역이다. 즉, 비동기 처리가 끝난 후 실행되어야 할 콜백 함수가 차례로 할당된다. 콜백 함수가 큐 안에 들어간다는 것이 포인트!
예를 들어 setTimeout에서 타이머 완료 후 실행되는 함수(1st 인자),
addEventListener에서 click 이벤트가 발생했을 때 실행되는 함수(2nd 인자) 등이 보관된다.

Queue(큐) : 자료 구조 중 하나, 선입선출(FIFO, Frist In Frist OUT)의 룰을 따른다.

Event Loop

우리가 이번에 본격적으로 알아볼 부분은 이 이벤트 루프가 어떻게 동작하는 지다.
큐에 할당된 콜백 함수를 순서에 맞춰 콜 스택에 할당해 주는 것 이다.
Event Loop는 Call Stack과 Callback Queue의 상태를 체크하여,
Call Stack이 빈 상태가 되면, Callback Queue의 첫번째 콜백을 Call Stack으로 밀어넣는다.
이러한 반복적인 행동을 틱(tick) 이라 부른다.

<2. 각각의 동작 원리 집중 분석>

01. Call Stack

예제.

<script>
function frist(){
   second ();
   console.log("첫 번째");
}
function second(){
   third ();
   console.log("두 번째");
}
function third(){
   console.log("세 번째");
}
first();
third();
</script>

Call Stack

담기고 빠져나가서 실행되는 순서1.
1. anonymous(우리가 코딩한 모든 코드가 가지고 있는 것)
2. frist()
3. second()
4. third()
5. console.log("세 번째")-> 실행되면서 빠져 나감.


담기고 빠져나가서 실행되는 순서2.
1. anonymous(우리가 코딩한 모든 코드가 가지고 있는 것)
2. frist()
3. second()
4. third()-> console.log("두 번째")-> 빠져나감.

담기고 빠져나가서 실행되는 순서3.

  1. second()->console.log("첫 번째")

담기고 빠져나가서 실행되는 순서4.
1. anonymous(우리가 코딩한 모든 코드가 가지고 있는 것)-> 최종적으로 사라짐.
2. third()-> 끝
3. console.log("세 번째") -> 출력


cf 우리가 콜 스택에서 만날 수 있는 에러.
1. Uncaught range error: maximum call stack size exceeded

이 에러는 우리가 아까 담았던 콜 스텍들이 하나 씩 담기다가 콜스텍마다 한계점이 있는데, 그 한계점을 초과하면, 이 해당 에러를 띄우면서 프로그램이 종료가 된다.

브라우저, 혹은 엔진 마다 콜스텍의 한계점이 다르고, 일반적으로는 1만 개를 가지고 있다. 크롬의 경우 약 12만 개를 갖고 있다.


2. 비동기적인 코드

이벤트 루프에서는 이 비동기 코드의 작동 방식이 핵심!!!!

<script>
console.log("시작")

setTimeout(function(){
	console.log("중간");
}, 3000);

console.log("끝")
</script>

<결과값 콘솔 창 출력 순서>
시작

중간

callstack
1.anonymous
2. console.log("시작")-> 그리고 실행이 되면서 콘솔에 "시작"이 찍힘.
3. 그 다음에 setTimeout(익명, 3초)가 들어감. -> 그런데 setTimeout함수는 비동기 함수다! -> 따라서 웹 api로 간다.
4. 그 다음에 콜스텍이 다음 줄 코드인 console.log("끝")을 쌓는다.
5. 웹 api에서는 동시에 3초를 돌리고 있을 것이다. 그동안 콘솔로그는 "끝"은 실행이 될 것. 그리고 다시 콘솔 쪽에 담길 것.
6. 이제 api는 3초가 지났다. 그러면 웹 api안에 있는 콜백함수 타임아웃을 콜백 큐로 넘겨준다.
7. 이벤트 루프가 콜 스텍을 검사한다. "어라? 비어있네?"
8. 그러면 이제 콜 스텍에 자신이 가지고 있는 익명 함수를 넘겨준다.

  1. 그러면 이제 익명 함수인 셋 타임아웃을 봤더니 콘솔로그가 있다.

  2. 다시 console.log("중간")를 스택에 쌓는다.

  3. 이후 다시 실행시켜서 콘솔에 마지막으로 찍는다.

  4. 그 다음 콜 스텍에 남아있던 익명 함수는 실행 종료. 해당 프로그램은 마무리가 되는 것.

예제2.

<script>
console.log("시작")

setTimeout(function(){
	console.log("중간");
}, 0);

console.log("끝")
</script>

<결과값 콘솔 창 출력 순서>
시작

중간
-> 다를 것 같지만, 동일하게 동작한다.

<콜스택 및 다른 이벤트 루프 작동 순서>
1. 콘솔로그가 시작되면서 콘솔에 시작이 찍힘.
2. 셋타임 아웃이 콜 스텍에 들어간다. 비동기 함수라서 결국 다시 웹 api로 들어간다.
3. 그리고 console.log("끝")이 콜스텍에 쌓인다.
주의! 여기서는 엔진 혹은 브라우저 환경에 따라서 실행이 달라진다.
4-1 console.log("끝")이 실행이 되어서 콘솔에 바로 찍힐 수도 있다.

혹은
4-2 아니면 웹 api가 먼저 끝나서 콜백 큐로 넘어갈 수도 있다.
->이 것을 전제로 하면 익명 셋 타임 함수가 콜백 큐로 넘어감.

  1. 단, 이렇게 되면 콜 스텍에 아직 어나니머스와 console.log("끝")이 남아있다. 콜백 큐에 있는 익명 함수는 콜 스텍에 넘어가지 못 한다.

  2. 콜스택은 계속 일을 진행. console.log("끝") 실행! -> 끝 콘솔에 출력 -> 어나니머스 종료.

  3. 이때서야 비로소 이벤트 루프가 콜스텍이 비워진 것을 보고 콜백 큐에 익명 함수를 콜스텍에 가져온다.

  4. 익명함수의 console.log("중간")이 콜스텍에 담겨진다. 그리고 다시 콘솔에 중간이 찍힌다. 익명 종료.

예제3.

<script>
console.log("시작")

setTimeout(function(){
	console.log("중간");
}, 0);

Promise.resolve()
  .then(function(){
  	console.log("프로미스");
    }
);

console.log("끝")
</script>

<콘솔 찍히는 순서>
1. 시작
2.
call stack
1. 어나니머스부터 콜 스텍에 찍힌다.
2. console.log("시작")찍힌다. -> 바로 실행 콘솔에 찍힌다.
3. settimeout(익명, 0초) 찍힌다. -> 비동기니까 api.

  1. promise 찍힌다. -> 여기서 주의!!!!! 프로미스는 비동기? NOPE!프로미스는 동기다!

프로미스 자체는 동기이지만, then을 만나는 순간. 비동기로 동작을 하게 된다!!!!! 지금 코드 상에서도 프로미스 안에 then이 있으니 엔진은 비동기로 인식한다.
5. 따라서 프로미스인 then(익명)을 웹 api로 넘겨서 타임 아웃 위에 쌓는다.
6. console.log("끝")이 콜 스텍에 쌓인다.

  1. 이번에도 역시 콘솔보다 웹 api가 먼저 실행된다고 가정하에 진행한다. 심지어 웹 api 상에서도 then이 먼저일 지 타임아웃이 먼저 일지는 알 수 없다. 타임아웃이 먼저 끝났다고만 가정.

  2. 콜백 큐에 익명 타임아웃을 넘긴다.

  3. 그 다음에 then이 콜백 큐로 넘어간다.

  4. 이제 이벤트 루프가 검사를 하는 것을 보면, 콜스텍에는 아직도 처리할 것들이 쌓여 있다. 콜스텍 처리 완료 기다린다.

  5. 콜스텍에서 console.log("끝") 출력. -> 콘솔에 "끝" 찍힘. 어나니머스 종료.

  6. 이제 이벤트 루프가 실시간 검사 중 드디어 콜스텍이 비었군~ 판단.

  7. 콜백 큐를 보면서 하나씩 가져다 쓴다.

  8. 자~ 여기서 잠깐만!

    이벤트 루프는 콜백 큐 중에 어떤 것을 먼저 가져다 쓸까? 우선 순위에 따라서 then을 먼저 가져다 쓴다! 아! 프로미스를 우선순위로 두는 구나만 여기서는 머릿 속에 담는다!

  9. 콜 스텍에 익명 함수 then을 가져온다. 그리고 console.log("프로미스")를 찍는다.-> 출력 프로미스를 콘솔에찍음. 그리고 익명을 종료.

  10. 콜스텍이 비었으니까 다시 콜백 큐에 있는 익명 타임아웃을 가져온다.

  11. 그리고 console.log("중간")을 콜스텍에 쌓고, 실행후 콘솔에 중간을 찍는다. 그리고 익명 타임아웃 종료. 마무리~


자~ 이제 콜백 큐에서 콜스텍으로 올리는 우선 순위에 대해 정리해 보자!

콜백큐는 사실 테스크 큐, 마이크로 테스크 큐, 에니메이션 프레임으로 이루어졌다고 한다. 테스크 큐 = 이벤트 큐라고 도하며, 마이크로 테스크 큐= 잡 큐라고도 한다.
일반적으로 프로미스는 마이크로 테스크 큐에 담긴다. 셋타임아웃은 테스크 큐에 담긴다.
Microtask Queue > Animation Frames > Task Queue 순으로 실행된다

마지막 예제.

<script>
console.log("시작")

setTimeout(function(){
	console.log("중간");
}, 0);

Promise.resolve()
 .then(function(){
 	console.log("프로미스");
   }
);

requestAnimationFrame(function(){
	console.log("requestAnimationFrame");
})

console.log("끝")
</script>

console 결과
1. 시작
2. 끝
3. 프로미스
4. requestAnimationFrame
5. 중간

이것으로 이번 비동기부터 시작한 대항해의 닻을 내린다. 나무에서 숲까지 돌아서 온 만큼 이제 백엔드 단에서 기본적인 웹의 진행 틀에 대해 조금이나마 배운 것 같다. 향후 백에 대한 토대가 될 것으로 생각하며 이만 다음 포스팅을 또 준비해야겠다.

----------------to be continued----------------

profile
개발도 예능처럼 재미지게~

0개의 댓글