코딩일상
[JavaScript 33가지 지식] 메시지큐와 이벤트 루프 본문
자바스크립트의 특징
자바스크립트는 싱글 스레드 기반의 언어이며 1개의 콜 스택을 사용한다.
1개의 콜 스택을 사용하기 때문에 하나의 함수의 작업이 오래 걸리게 되면
그 이후에 실행될 다른 작업들은 실행이 되지 못하는 상황이 발생하게 된다.
이 문제를 해결하기 위하여 비동기 콜백 방식을 사용하고 있다.
이와 관련된 내용이 메시지 큐와 이벤트 루프다.
들어가기 앞서
자바스크립트는 콜스택과 메모리 힙이라는 메모리 구조를 통해 데이터 및 코드 실행을 관리한다.
1. 콜스택(Call Stack)
- 원시타입(숫자 등) 데이터가 저장된다.
- 실행컨텍스트(Execution Context)를 통해
- 변수 식별자(이름) 저장
- 스코프 체인 및 this 관리
- 코드 실행 순서 관리 등을 수행.
실행 콘텍스트(Execution Context)란?
자바스크립트가 코드를 실행하기 위해 관리하는 Stack구조의 실행 환경이라고 볼 수 있습니다.
자바스크립트는 실행컨텍스트라는 구조를 통해 실행 시점의 변수, 함수, this, 스코프 등을 관리하며 명령어를 실행해 나갑니다.
2. 메모리힙(Memory Heap)
- 참조 타입(객체 등) 데이터가 저장된다.
원시 타입은 콜 스택에 저장되고, 참조 타입은 메모리 힙에 저장된다.
메시지 큐
메시지 큐는 자료구조 큐(Queue)를 기반으로 구성되어 있다.
큐는 먼저들어온 것이 먼저 나가는 FIFO(First In First Out)의 특징을 갖는다.
자바스크립트의 브라우저 엔진의 메시지 큐에는 비동기로 처리될 콜백 함수가 저장된다.
콜스택이 비어있게 되면 메시지 큐에 있는 콜백 함수를 꺼내와 실행하게 된다.
메시 지큐에서 콜백 함수를 꺼내오는 이 과정은 이벤트 루프가 담당한다.
이벤트 루프
이벤트 루프는 콜 스택이 비어있으면 메시지 큐에서 콜백 함수를 꺼내 실행하는 역할을 한다.
while(queue.waitForMessage()){
queue.processNextMessage();
}
queue.waitForMessage() 함수는 현재 처리할 수 있는 메시지가 존재하지 않으면 새로운 메시지가 도착할 때까지 동기적으로 대기합니다.
참고)
큐와 이벤트 루프는 자바스크립트 자체 엔진이 아닌 브라우저나 Node.js에 있습니다.
Node.js는 브라우저 API 같은 비동기 IO를 지원하기 위해 libuv 라이브러리를 사용하며, 이 libuv가 이벤트 루프를 제공
메시지 큐 와 이벤트 루프 예제
setTimeout을 이용해 비동기 적인 흐름을 작성해볼 수 있다.
예시 1)
const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"), 500);
const baz = () => console.log("Third");
bar();
foo();
baz();
간단하게 먼저 순서를 알아봅시다.
- bar()가 먼저 콜 스택에 들어옵니다.
- bar() 안의 내부 함수 setTimeout()이 스택에 들어오고 console.log를 실행시킵니다.
- setTimeout()은 WEP API의 기능을 이용하여 스택의 바깥 어딘가로 이동이 되어 함수의 기능처럼 정해진 시간 동안 대기합니다.
- setTimeout()은 사라지고 bar()은 스택에서 팝이 됐으니 foo() 함수가 스택에 호출됩니다.
- 콜 스택에서 일이 처리되는 동안 setTimeout()은 정해진 시간이 다되면 Queue로 이동됩니다.
- 이제 foo()도 팝 되고 baz()도 팝이 되어 콜 스택이 비었습니다. 그때에 큐에서 이벤트 루프를 이용!
콜 스택에 setTimeout()을 보냅니다. - 콜스 텍에 보내진 setTimeout()은 기능을 하고 팝 됩니다.
예시 2)
위와 같이 setTimeout함수에 1000ms를 주어 실행하게 되면 1초 뒤에 bar가 출력되는 것을 확인할 수 있다.
function foo() {
console.log('foo')
}
setTimeout(function bar() {
console.log('bar')
}, 1000)
foo()
//foo
//... after 1sec ...
//bar
예제 2-1)
setTimeout에 0ms를 주어 실행하면 bar부터 출력이 될 것 같지만 그렇지 않다.
function foo() {
console.log("foo");
}
setTimeout(function bar() {
console.log("bar");
}, 0);
foo();
//foo
//bar
foo가 먼저 출력이 된 후 bar가 출력이 되는 것을 확인할 수 있다.
setTimeout을 사용하게 되면서 bar함수는 메시지 큐에 들어가게 된다.
그 후 foo함수는 콜 스택에 들어가게 된다. 그림으로 표현하면 아래와 같다.
이 과정에서 foo함수가 먼저 실행이 되고 콜 스택이 비어있게 되면
이벤트 루프가 bar함수를 콜 스택에 추가해주게 된다.
레퍼런스
콜 스택/메모리 힙
목차
'개발 공부 > JavaScript 33가지 필수지식' 카테고리의 다른 글
[JavaScript 33가지 지식]IIFE,Modules, Namesapeces (0) | 2022.12.02 |
---|---|
[JavaScript 33가지 지식]식(expression)vs 문(statement) (0) | 2022.12.02 |
[JavaScript 33가지 지식]함수범위, 블록범위, 렉시컬 범위 (0) | 2022.12.01 |
[JavaScript 33가지 지식] == vs === vs type of (0) | 2022.12.01 |
[JavaScript 33가지 지식] 명시적변환, 암시적 변환, 명칭적 타이핑, 구조적 타이핑, 덕 타이핑 (0) | 2022.11.30 |