개발/Javascript

[자바스크립트] 이벤트 루프와 비동기 작업 (그리고 단어 설명)

duknock 2024. 4. 26. 19:01
반응형

 
자바스크립트는 싱글스레드 환경에서 실행된다.
 
즉, 하나의 호출 스택을 통해 함수 호출을 처리하기 때문에, 한번에 하나의 작업만 처리할 수 있다.
 
하지만 우리는 이미 비동기 함수라는 것을 많이 사용하고 있다.(setTimeout, ajax(fetch), 웹 워커 등)
 
비동기 함수를 사용하면 여러개의 작업을 순차적으로 기다리지 않고 한번에 병렬적으로 처리 가능하다.

엥? 한번에 하나의 작업만 처리 가능하다면서 어떻게 비동기 작업을 처리함?

 
왜냐하면 자바스크립트에서는 비동기적인 작업은 메인스레드가 아닌 백그라운드 스레드로 보내서 처리시키기 때문이다.
(다른 놈[브라우저]한테 짬때리는 거다)
 
📢 이 때 주의할 점 하나는, 비동기 함수 자체를 백그라운드 스레드로 보내는 것이 아니다!
백그라운드 스레드로 보내는 것은 비동기 작업이다.
setTimeout()과 같은 함수 자체는 동기적으로 처리된다.
 
예시) 파란색은 동기적, 빨간색은 비동기적 업무 라고 보면 된다
 
상사가 업무메일을 받고 메일에 쓰여져 있는 업무를 후임한테 짬때린다.
상사는 메일에 쓰여진 업무를 후임한테 시키는 것이지, 메일을 받는 행위 자체를 후임한테 시키는 것이 아니다.
 
 
그리고 이런 비동기 작업을 관리하는 것이 이벤트 루프인데,
 
이벤트 루프란 호출스택, web API(백그라운드 스레드), 태스크 큐 등의 요소들을 모니터링하며 비동기 작업을 관리하고 실행하는 메커니즘이다.
 

잠시만, 왜 갑자기 '큐', '스택'이니 '스레드'니 하면서 어려운 단어 씀?
난 컴공과 전공이 아니라서 그런 단어 몰라요

 

큐(Queue)

큐는 선입선출(FIFO, First In, First Out) 원칙에 따라 동작하는 데이터 구조이다.(물리적인 메모리가 아니다. 개념이다.)
이는 먼저 추가된 요소가 먼저 제거되는 구조를 가지고 있다.
편의점에서 냉장고에 음료수를 채울 때, 워크인 냉장고로부터 뒤에서부터 채우면 먼저 채워놓은것들이 앞으로 가는 원리와 같다.
 

스택(Stack)

스택은 후입선출(LIFO, Last In, First Out) 원칙에 따라 동작하는 데이터 구조이다.(얘도 개념이다.)
예시를 들자면 상자에 물건을 쌓는 모습을 생각하면 된다.
마지막에 넣은 물건이 맨 위에 위치하고, 물건을 빼낼 때는 맨 위에서 부터 빼낸다.
 

스레드(Thread)

스레드는 컴퓨터 프로그램이 동시에 여러 작업을 수행할 수 있도록 하는 실행 단위이다.
일반적으로 각 스레드는 하나의 호출 스택을 가지고 있다.
호출 스택은 함수 호출의 순서를 기록하는 데이터 구조로, 현재 실행 중인 함수의 정보를 저장한다.
스레드는 이 호출 스택을 사용하여 코드를 실행하고, 함수 호출이 발생할 때마다 호출 스택에 새로운 프레임을 추가하고, 함수가 완료되면 해당 프레임을 제거한다.
 


 

우리는 지금부터 이벤트루프의 작동 과정을 로우레벨로 분석할 것이다.
솔직히 단순 코딩할 때는 몰라도 되는 부분이지만,
작동 원리를 알고 있으면 개발할 때 분명히 도움이 된다.

 
 
예시를 들어보자

setTimeout(()=>{
	console.log('hello');
}, 1000)
console.log('bye')

 
위 코드가 실행되면 어떻게 될까?

// 콘솔 출력 "bye"
// 1초 후 콘솔 출력 "hello"

 
뭐 당연히 이렇게 콘솔에 찍히겠지
 
근데 이 과정에서 브라우저 엔진 내에서는 어떻게 처리가 되는지 알아보면
 
1. setTimeout() 함수가 호출스택에 쌓인다.
2. setTimeout() 함수가 실행되면서 백그라운드 스레드(타이머)를 부른다.(야 너 1초 세라!)
3. 이벤트 루프는 호출스택에서 setTimeout() 함수에 할당된 콜백 함수 ()=>{console.log('hello')}를 꺼내서 백그라운드 스레드(타이머)에게 넘겨준다.
4. 백그라운드 스레드(타이머)는 시간을 잰다.(1초 동안)
5. setTimeout() 함수는 할일을 다 했으니 호출스택에서 제거된다.
6. console.log('bye') 함수가 호출스택에 쌓인다.
7. console.log('bye') 함수는 바로 실행되면서 호출스택에서 제거된다. (이제 호출스택이 완전히 비었다.)
8. 1초가 지난 후 백그라운드 스레드(타이머)가 할일을 끝냈다고 감지한 이벤트 루프콜백 함수를 태스크큐로 옮긴다.
9. 호출스택이 비어있다고 감지한 이벤트 루프가 태스크큐에 있는 콜백함수를 호출스택으로 옮긴다.
10. 콜백함수가 실행되며 호출스택에서 제거된다.
 
 
이렇게 복잡한 과정이 진행된다
 
글로 써놓으니 이해하기 어렵다면 아래 코드와 이미지를 참고하자

const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"), 500);
const baz = () => console.log("Third");

bar();
foo();
baz();
출처 :https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif

 
 
 요약하자면 이벤트 루프는 각 요소들을 계속 모니터링 하면서 비동기 함수 작업이 호출스택에 쌓이면 이를 Web API(백그라운드 스레드)로 옮기고

작업이 완료되면 콜백을 태스크큐로 옮기고, 이를 다시 호출스택으로 옮기는 역할을 한다.

이 작업은 끊임없이 반복되기 때문에 이벤트'루프' 라고 하는 것이다.




반응형