이전 글
[자바스크립트] 동기와 비동기
동기와 비동기 동기 Synchronous : 동시에 발생하는 순차적, 직렬적으로 태스크를 수행한다. 요청을 보냈다면, 응답을 받아야 다음 동작이 이루어진다. 순차적으로 실행되기 때문에, 어떤 작업이 수
gobae.tistory.com
console.log("Hello");
setTimeout(() => {
console.log("James");
}, 4);
console.log("World");
let i = 0;
while (i < 1e9) i++;
console.log("Finish");
이 코드의 결과는
Finish 뒤에 James가 출력된다!
분명 0.004초 뒤에 "James"를 출력하도록 설정했다.
음.... while문이 1e9횟수 돌아가는게 0.004초보다 빠를까..?
아니다!
심지어는 while문이 다 끝나고, Finish까지도 출력하고, James가 출력되었다.
이것을 이해하기 위해선, 이벤트 루프와 태스크 큐를 배우면 된다.
먼저, 자바스크립트 엔진을 살짝 알아보자. 이벤트루프와 태스크 큐와 관련이 있다.
자바스크립트 엔진
자바스크립트 엔진은 크게 2개의 영역, 콜스택, 힙 으로 구성된다.
콜 스택(= 실행 컨텍스트 스택)
소스코드 평가 과정에서 생성되는 실행 컨텍스트가 추가/제거되는 스택구조다.
실행 컨텍스트가 push/pop 되므로 실행 컨텍스트 스택이라고도 한다.
Tmi. 실행 컨텍스트는 자바스크립트 엔진이 코드를 평가/실행하는 단위. 이후에 스코프와 연관된다.
함수 호출 시 함수의 실행 컨텍스트가 생성되며 순차적으로 콜스택에 push되고, 실행된다.
만약 A함수 실행 컨텍스트를 실행 도중에 B함수가 실행되면??
B함수의 실행 컨텍스트가 콜스택에 push되어 실행된다.
결국에는 스택의 LIFO(Last In First Out) 특성으로 인해,
가장 최근에 들어온 실행 컨텍스트가 가장 먼저 완료된다.
즉 가장 나중에 push된 실행 컨텍스트부터 종료되면 콜스택에서 제거된다.
모든 실행 컨텍스트가 push/pop 거치며 스택이 비어있으면 모든 실행이 끝난 것이다.
복잡한 용어들이 많아서, 이해가 힘들 수 있다.
이것도 결국 코드로 보면 쉽다.
function A(){
B();
console.log("function A");
}
function B(){
console.log("function B");
}
A();
// 실행결과
// function B
// function A
"A함수를 실행하고, A함수 안에서 B함수를 실행하는 과정"을 엄청나게 어려운것 처럼 풀어놨을 뿐이다.
당연히 "도대체 안에서 어떻게 돌아가는건데?"를 이해하는 과정이라 힘들 수 있다. 화이팅!
힙
동적으로 생성되는 객체가 저장되는 메모리 공간이다.
콜스택에 쌓여 있는 실행 컨텍스트들은 힙에 저장된 객체를 참조하고 있다.
프로세스 메모리 개념에서, 힙 공간을 생각하면 된다.
값이 정해진 원시값(int, char, boolean...) 등과는 달리 객체는 크기를 정할 수 없다.
할당 크기가 런타임 시 결정된다. 그 때 힙에 저장해서 참조하는 방식으로 사용한다.
이처럼 자바스크립트 엔진은 작업을 실행 컨텍스트 단위로 나누고, 콜스택으로 순차 실행한다.
엔진은 항상 코드를 "순차적으로 실행한다".
그래서 비동기 작업을 돕는 다른 장치가 필요했고, 이것이 이벤트 루프와 태스크 큐이다.
이벤트 루프와 태스크 큐는 자바스크립트 엔진에 있지 않다.
런타임(실행환경)인 브라우저/NodeJS에 내장되어 있다.
이제 본 글의 목적인 이벤트 루프와 태스크를 이해해보자!
이벤트 루프와 태스크 큐
자바스크립트는 싱글 스레드 + 동기방식으로 동작한다.
그래서 한 번에 하나의 작업만 처리하도록 동작한다.
하지만 막상 네이버를 들어가보면?
여러 작업들이 동시다발적으로 일어나는 듯 보인다.
이 동시성을 가능하도록 하는 조력자가 이벤트 루프다.
이벤트 루프
이벤트 루프는 Loop이다. 코드의 while문 같이 계속 반복하겠다는 것이다.
현재 콜스택에 실행중인 실행컨텍스트가 있는지, 태스크큐에 대기중인 콜백함수가 있는지를 확인한다.
콜스택이 비어있고 태스크 큐에 대기중인 콜백이 있다면?
이벤트 루프는 FIFO로 태스크 큐에 대기중인 콜백을 콜스택으로 이동시킨다.
콜스택으로 이동한 함수는, 자신의 실행 컨텍스트를 만들며 자바스크립트 엔진에 의해 순차적으로 처리된다.
태스크 큐
비동기 함수의 콜백함수/이벤트핸들러가 일시적으로 대기하는 큐다.
큐 자료구조다. 그래서 FIFO(First In First Out)로 동작한다.
비동기 함수? setTimeout같은 타이머 함수, AJAX 수행 함수, async 키워드가 붙은 함수 등이 있다.
이벤트 루프가 태스크 큐에 순차적으로 쌓인 콜백들을 순차적으로 가져와 콜스택에 밀어준다.
이제 배운 개념들을 가지고, 글 서두의 코드를 이해해 볼 차례다.
코드를 이해해보자
console.log("Hello");
setTimeout(() => {
console.log("James");
}, 4);
console.log("World");
let i = 0;
while (i < 1e9) i++;
console.log("Finish");
이제 내부 동작을 이해했으니, 위의 출력이 나오는 이유를 알 수 있다.
- 전역 실행 컨텍스트가 생성되고 콜스택에 push
- 전역 실행 컨텍스트의 첫 문단인 console.log("Hello"); 함수가 호출
- 다음 코드 setTimeout 함수 호출
- setTimeout 함수의 실행 컨텍스트가 콜스택에 push되면, 타이머 호출을 스케쥴링하고 바로 콜스택에서 pop된다.
- 브라우저가 타이머 만료 뒤 태스크 큐에 콜백함수console.log("James")를 넣어준다.
- 태스크 큐에 콜백함수가 있으나, 아직 콜스택이 비어있지 않으므로 콜백이 실행되지 않는다.
- 다음 코드 console.log("World"); 가 수행된다.
- let i~ while~ console.log(Finish)까지 수행된다.
- 와중에도 이벤트 루프는 계속 콜스택과 태스크 큐를 살펴본다.
- 그러나, 전역 컨텍스트가 콜스택에 계속 남아있음을 알고있다.
- console.log(Finish)까지 끝나야 전역 실행 컨텍스트가 콜스택에서 pop된다.
- 콜스택에 비어있고, 태스크 큐에 콜백이 존재한다. 그럼 이벤트루프가 역할을 수행한다.
- 브라우저가 태스크 큐에 넣어둔 콜백을 이벤트 루프가 콜스택에 push한다.
- 콜백의 실행 컨텍스트가 생성되어 콜스택에 push되고 작업을 수행한 후에 콜스택에서 pop된다.
그러므로, 결국 "James"가 가장 마지막에 출력된다.
이제는 setTimeout 타이머가 왜! 정해진 시간에 동작하지 않는 경우가 발생하는지 이해할 수 있다.
또한
let name;
setTimeout(() => {
name = "James";
}, 1000);
console.log(name);
왜 "undefined"를 출력하는지 이해하는 것도 껌이다.
간단하게 자바스크립트 엔진, 이벤트 루프, 콜스택을 통해서 비동기 함수가 이상하게 실행되는 이유도 알아봤다.
자바스크립트 엔진은 싱글 스레드로 동작하지만, 브라우저는 멀티 스레드로 동작한다.
다음 포스팅에서는 비동기 작업을 만드는 방법에 대해서 알아보자.
참고한 사이트
https://wikibook.co.kr/mjs/
https://it-eldorado.tistory.com/86
https://kyounghwan01.github.io/blog/JS/JSbasic/eventLoop/#ecmascript에는-이벤트-루프가-없다
이어지는 포스팅
[자바스크립트] 비동기로 데이터 가져오기, 콜백 헬
이전 포스팅 [자바스크립트] 비동기 작업, 이벤트 루프와 태스크 큐 이전 글 [자바스크립트] 동기와 비동기 동기와 비동기 동기 Synchronous : 동시에 발생하는 순차적, 직렬적으로 태스크를 수행한
gobae.tistory.com
'JavaScript > theory' 카테고리의 다른 글
[자바스크립트] 프로미스 객체 (0) | 2021.08.22 |
---|---|
[자바스크립트] 비동기로 데이터 가져오기, 콜백 헬 (0) | 2021.08.22 |
[자바스크립트] 동기와 비동기 이해하기. (1) | 2021.08.21 |
[자바스크립트] enum을 배우고 구현해보자. (0) | 2021.08.02 |
[자바스크립트] XML과 JSON 포맷 배우기 (0) | 2021.08.01 |