-
자바스크립트 엔진과 이벤트 루프TIL/프로그래머스 웹 데브코스 2021. 8. 18. 22:21728x90
대표적으로 자바스크립트는 '단일 스레드' 기반의 언어이다.
스레드가 하나라는 말은 동시에 하나의 작업만을 처리할 수 있다는 의미이다.
하지만 모두 알다시피 자바스크립트에서는 비동기 처리가 가능하다.
우리는 특정 웹 페이지에서 애니메이션 효과를 보여줌과 동시에 마우스나 키보드의 입력을 받아 처리하고 웹 페이지상에서 여러 개의 작업을 동시에 할 수 있다는 것을 잘 알고 있다.
또한, Node.js 기반의 웹 서버에서 동시에 여러개의 HTTP 요청을 처리하기도 한다.
이는 브라우저 위에서 동작하는 자바스크립트라는 언어가 HTML과 CSS를 핸들링하며 동적인 웹 페이지를 만들기 때문이라 생각한다.
위에서 단일 스레드로 동시의 하나의 작업만을 처리 할 수 있다고어떻게 이러한 비동기 처리가 가능한 걸까?
결론부터 말하자면 자바스크립트 엔진을 구동하는 환경
즉, 브라우저, Node.JS가 자체적으로 관리하고 있는 이벤트 루프 덕분에 비동기 처리가 가능하다.
자바스크립트 엔진
자바스크립트 엔진은 자바스크립트 코드를 해석하고 실행하는 인터프리터이다. (대표적으로 V8 엔진이 있다)
자바스크립트는 단일 스레드 언어로, 보통 자바스크립트의 함수가 실행되는 방식을 보통
"Run To Completion"이라 말한다.
이는 하나의 함수가 실행되면 이 함수의 실행이 끝날 때까지 다른 어떤 작업도 중간에 끼어들지 못한다는 의미이다.
자바스크립트 엔진은 하나 즉, 단일 호출 스택을 사용하며 현재 스택에 쌓여있는 모든 함수들이 실행을 마치고 스택에서 제거되기 전까지는 다른 어떠한 함수도 실행될 수 없다.
자바스크립트 엔진은 아래와 같이 이루어져 있다.
Heap은 메모리 할당이 일어나는 부분이며
Call Stack은 자바스크립트의 단일 호출 스택으로 코드가 실행될 때 Stack이 쌓이는 부분이다.
자바스크립트 엔진에는 코드가 실행될 때 그 위치를 나타내느 커서(cursor) 역할을 하는 Call Stack이 있다.
- 전체 main 코드 블록이 스택에 쌓인다.
- helloJsConf 함수가 호출되어 스택에 쌓인다.
- hello 함수가 호출되어 스택에 쌓인다.
- console.log('hello')가 스택에 쌓인다.
- ‘hello’를 콘솔에 출력함으로써 console.log('hello')는 스택에서 제거된다.
- hello 함수가 스택에서 제거된다.
- console.log('JSConfKorea')가 스택에 쌓인다.
- ‘JSConfKorea’를 콘솔에 출력함으로써 console.log('JSConfKorea')는 스택에서 제거된다.
- helloJSConf 함수도 일을 모두 마쳤으니 스택에서 제거된다.
- main 코드 블록이 스택에서 제거된다.
만약 굉장히 오래 걸리는 작업이 있다면 어떨까?
이전 예제와 같이 오래 걸리는 작업이 있다면 hello나 jsConfKorea 메시지를 출력하는 일에 지연이 발생할 것이다.
이러한 동시성 문제를 이벤트 루프가 해결 해준다!
Node.js와 브라우저 환경은 아래와 같다.
Node.js의 경우 위처럼 비동기 I/O를 지원하기 위해 libuv 라이브러리를 사용하며, 이 libuv가 이벤트 루프를 제공한다.
자바스크립트 엔진은 비동기 작업을 위해 Node.js의 API를 호출하며, 이때 넘겨진 콜백은 libuv의 이벤트 루프를 통해 스케줄 되고 실행된다.
- Wep APIs : 브라우저에서 지원하는 APIs.
- Callback Queue : Task Queue, Microtask Queue, Animation Frames가 있다.
여기서 Task는 브라우저 혹은 그 외 구동 환경에서 순차적으로 실행되어야 하는 작업을 의미한다.
- Envet Loop : 자바스크립트 엔진의 Call stack이 비어있을 경우(처리할 작업이 X)
Queue에 있는 Callback 함수를 자바스크립트 엔진의 Call Stack으로 집어넣는 역할을 한다.
Wep APIs
브라우저에서 지원하는 API이다.
DOM 이벤트(클릭, 새로고침...)
네트워크 호출 (AJAX)
Timer (setTiemout)
등을 실행시킬 경우 브라우저에 위임된다.
특정 작업이 완료되면 자바스크립트 엔진으로 전달받은 Call back 함수를 Queue로 넘겨준다.
Callback Queue
Wep API에서 작업이 완료된 후 해당 작업의 Callback 함수가 있다면 Callback 함수를 Queue로 전달하는데
Callback Queue는 전달받은 Callback 함수를 저장하고 있다가 Event Loop에 의해 자바스크립트 엔진의 CallStack으로 옮겨지게 된다.
이때 Queue는 Microtask Queue, Animation Frames, Task Queue 3종류가 있으며 이는 브라우저, Node.JS가 자체적으로 관리하고 있다고 한다.
Microtask Queue
Task Queue와 마찬가지로 Callback 함수가 들어간다는 점에서 동일하지만 어떤 함수를 실행하느냐에 따라 분기가 달라지게 된다.
아래의 Callback 함수들이 Wep API에서 Callback Queue로 전달될 때 Microtask Queue로 전달된다.
이 중 Promise 함수가 전달됨을 주의 깊게 보자.
- process.nextTick, Promise, Object.observe, MutationObserver
Task Queue
Microtask Queue와 마찬가지로 Callback 함수가 들어간다는 점에서 동일하지만 어떤 함수를 실행하느냐에 따라 분기가 달라지게 된다.
아래의 Callback 함수들이 Wep API에서 Callback Queue로 전달될 때 Task Queue로 전달된다.
- setTimeout, setInterval, setImmediate 등 대다수의 Callback 함수를 전달받는다.
비동기 작업을 위해 브라우저는 Task Queue 뿐 아니라 Microtask Queue, Animationn frames도 함께 관리한다고 한다.
Animationn frames
브라우저에게 수행하기를 원하는 특정 애니메이션 관련(requestAnimation) Callback 함수를 저장하는 Queue이다.
관련하여 아래를 참조하면 좋다.(https://sculove.github.io/post/javascriptflow/)
이벤트 루프
Loop의 의미는 반복, 순환으로 계속 반복해서 Call Stack과 Queue 사이의 작업들을 확인하고 Call Stack이 비어있는 경우 Queue에서 작업을 꺼내 Call Stack으로 넣으며 이 과정을 스크립트가 종료될 때까지 반복한다.
이때 Event Loop가 Queue에서 작업을 꺼내 Call Stack으로 넣어주는 과정을 Tick (틱)이라고 부르며
Event Loop는 Microtask Queue → Animation frames → Taske Queue 순으로
우선순위를 두고 작업을 가져온다!
Event Loop에서 Call Stack에서 처리할 작업이 없을 경우 위의 순서대로 탐색을 하며 작업을 Call Stack에 넘겨준다.
이때, Animation frames 작업이 완료되면 브라우저 렌더링 작업이 이루어진다!!
이벤트 루프가 어떻게 동작하는지 간략히 설명하자면
1. 처리할 작업이 있다면 그중 가장 오래된 작업을 실행한다.
2. 처리할 작업이 없다면 다음 작업을 기다린다.
3. 다시 처리할 작업이 있다면 1번으로 돌아가 이 과정을 반복한다.
이때 Wep API로부터 어떤 Callback 함수를 받는지에 따라 각각의 Queue에 전달되고
이벤트 루프는 우선순위에 따라서 틱을 수행하게 된다.
자바스크립트 엔진의 Call Stack도 비고 런타임 환경의 Queue가 모두 비어있다면 작업이 종료된다.
이처럼 Event Loop와 Queue는 자바스크립트 엔진이 하나의 코드 조각을 하나씩 처리할 수 있도록 작업을 스케줄 하는 동시에 비동기 작업을 할 수 있도록 도와준다.
즉, 자바스크립트는 싱글 스레드로 비동기 처리를 할 수 없는 녀석이지만,
브라우저, Node.JS(Wep APIs, Callback Queuu, Event Loop의 도움으로
비동기 처리를 할 수 있다. (비동기적으로 처리하는 것처럼 보일 수 있다!)
출처
https://meetup.toast.com/posts/89
https://engineering.linecorp.com/ko/blog/dont-block-the-event-loop/
728x90'TIL > 프로그래머스 웹 데브코스' 카테고리의 다른 글
webpack 이란 무엇인가? (0) 2021.09.17 JS_명령형 프로그래밍과 선언형 프로그래밍 (0) 2021.08.17 JS_잘 틀리는 예제 (0) 2021.08.16 JS_Promise (0) 2021.08.14 JS_코드를 값으로 다루는 go, pipp, curry 함수 (0) 2021.08.12