이벤트 루프
1) 비동기 작업과 호출 스케줄링
자바스크립트는 싱글 쓰레드 환경에서 동작하는 언어이다. 즉, 한 번에 하나의 작업만 처리할 수 있다. 하지만 브라우저 환경이나 Node.js에서 비동기 작업(예: 파일 읽기, 네트워크 요청)을 처리해야 할 때, 자바스크립트는 이벤트 루프(Event Loop)를 이용해 동시성(Concurrency)을 지원한다.
이벤트 루프는 자바스크립트의 비동기 처리에서 핵심 역할을 하는 메커니즘으로, 자바스크립트가 멈추지 않고 여러 작업을 처리할 수 있도록 도와준다. 콜스택(Call Stack), 태스크 큐(Task Queue), 그리고 이벤트 루프가 함께 협력하여 이러한 비동기 작업들을 효율적으로 처리한다.
흐름을 간단하게 살펴보자면:
- 싱글 쓰레드로 동작하는 자바스크립트는 하나의 작업을 콜스택에 담아 처리한다.
- 비동기 작업이 발생하면 해당 작업을 바로 처리하지 않고, 콜백 함수를 등록한 후 그 작업이 완료될 때까지 기다린다.
- 작업이 완료되면, 그 작업에 등록된 콜백 함수가 태스크 큐에 들어간다.
- 이벤트 루프는 콜스택이 비어 있는지 확인한 후, 비어 있으면 태스크 큐에서 작업을 하나씩 꺼내 콜스택으로 전달하여 실행한다.
이 흐름을 통해 자바스크립트는 싱글 쓰레드 환경에서도 동시성 처리를 가능하게 한다.
자바스크립트는 기본적으로 동시성 처리를 지원하지 않지만, 이벤트 루프 덕분에 비동기 작업을 처리하면서 동시에 여러 작업을 수행할 수 있는 것처럼 보이게 된다. 동시성(Concurrency)은 비동기 작업들이 동시에 실행되는 것이 아니라, 여러 작업이 효율적으로 분배되고 처리되면서 마치 동시에 이루어지는 것처럼 느껴지게 하는 것이다.
콜백 함수는 특정 작업이 끝난 후 실행되는 함수이다. 자바스크립트에서는 비동기 작업을 할 때 콜백 함수를 자주 사용한다. 이벤트 루프는 이러한 비동기 작업이 끝났을 때 해당 콜백 함수를 태스크 큐에 넣고, 콜스택이 비어 있을 때 그 콜백을 실행해준다.
즉, 이벤트 루프는 콜백 함수가 적절한 시점에 실행되도록 관리해주는 역할을 한다.
예시)
console.log("Start");
setTimeout(() => {
console.log("Inside setTimeout");
}, 0);
console.log("End");
1. 콜스택에서 동기 코드 실행
자바스크립트는 코드를 위에서 아래로 실행합니다. 먼저, 콜스택(Call Stack)에 동기적인 코드가 올라갑니다.
- console.log("Start")가 실행되어 콜스택에 쌓이고, "Start"라는 문자열이 출력됩니다. 실행이 끝나면 콜스택에서 제거됩니다.
- 출력: Start
- setTimeout 함수가 호출됩니다. 이 함수는 비동기 함수이므로 바로 실행되지 않습니다. setTimeout이 호출되면, 콜백 함수(이 경우 () => console.log("Inside setTimeout"))는 **태스크 큐(Task Queue)**에 추가될 준비를 하게 됩니다.
- 이 시점에 콜백 함수는 아직 실행되지 않고, 대기 상태에 있습니다.
- console.log("End")가 호출됩니다. 이 역시 동기 함수이기 때문에 바로 콜스택에 쌓여 실행되고, "End"가 출력됩니다. 실행이 끝나면 콜스택에서 제거됩니다.
- 출력: End
2. 태스크 큐로 이동
setTimeout(() => { console.log("Inside setTimeout") }, 0)의 콜백 함수는 지정된 0밀리초 이후에 태스크 큐에 들어갑니다. 여기서 중요한 점은 콜백 함수가 0밀리초 뒤에 태스크 큐로 들어간다는 것이지, 즉시 실행된다는 뜻은 아닙니다.
3. 이벤트 루프가 콜백을 실행
이제 **이벤트 루프(Event Loop)**가 콜스택을 감시합니다. 콜스택이 비어 있을 때, 태스크 큐에서 대기 중인 작업을 콜스택으로 옮깁니다.
- console.log("End")가 실행된 후, 콜스택이 비게 됩니다.
- 이벤트 루프는 태스크 큐에서 setTimeout의 콜백 함수를 발견하고, 이를 콜스택에 올려 실행합니다.
- 그 결과 "Inside setTimeout"이 출력됩니다.
- 출력: Inside setTimeout
출력 결과
Start
End
Inside setTimeout
실행 흐름 요약
- 동기적인 코드 console.log("Start")와 console.log("End")는 바로 실행된다.
- setTimeout으로 전달된 콜백 함수는 0밀리초 뒤에 태스크 큐에 추가된다.
- 동기적인 코드가 모두 실행되고 나서야, 이벤트 루프가 태스크 큐에 있는 콜백 함수를 실행한다.
- 마지막으로 "Inside setTimeout"이 출력된다.
2) 이벤트 루프와 프레임 속도
브라우저 환경에서 자바스크립트는 이벤트 루프와 화면 렌더링 주기(Frame Rate) 간에도 상호작용이 있다. 브라우저는 일반적으로 1초에 60번 화면을 갱신하며(60 FPS), requestAnimationFrame(rAF) 같은 메서드는 이 화면 갱신과 동기화하여 애니메이션을 최적화하는 역할을 한다.
rAF(RequestAnimationFrame)은 브라우저가 화면을 다시 그릴 때 실행될 코드를 예약하는 함수이다. 주로 애니메이션을 부드럽게 처리하기 위해 사용된다.
- setInterval은 주기적으로 코드를 실행하지만, 브라우저의 화면 렌더링 주기와는 맞지 않을 수 있다.
- 반면에, rAF는 브라우저의 리프레시 속도에 맞추어 애니메이션을 처리하기 때문에 더 부드러운 화면 전환을 가능하게 한다.
rAF를 사용한 애니메이션의 장점
- 최적화된 성능: 브라우저가 화면을 다시 그릴 준비가 되었을 때만 함수가 실행되기 때문에 CPU와 메모리 자원을 아낄 수 있다.
- 더 부드러운 애니메이션: 브라우저의 프레임 속도와 동기화되어 애니메이션이 끊기지 않고 자연스럽게 동작한다.
3) Micro Task Queue와 Macro Task Queue (태스크 큐의 우선순위)
Micro Task Queue와 Macro Task Queue는 태스크 큐를 나누는 두 가지 방식이다.
- Micro Task Queue: 여기에는 Promise의 .then이나 MutationObserver 등의 작업들이 저장된다. 마이크로 태스크는 콜스택이 비면 바로 실행된다.
- Macro Task Queue: 여기에는 setTimeout, setInterval, 이벤트 핸들러 등의 작업들이 저장된다. 매크로 태스크는 마이크로 태스크보다 나중에 실행된다.
이벤트 루프는 콜스택이 비면 먼저 Micro Task Queue에 있는 작업들을 모두 처리하고, 그 다음에 Macro Task Queue에 있는 작업을 처리한다.
'JavaScript' 카테고리의 다른 글
JavaScript - 코어 자바스트립트 정리 (1~3장, 데이터 타입& 실행 컨텍스트& this) (2) | 2024.09.19 |
---|---|
JavaScript - 자바스크립트 메모리 관리와 객체 참조 모델 (2) | 2024.09.17 |
JavaScript - this (0) | 2024.09.02 |
JavaScript(JS) 자바스크립트 동작원리 (0) | 2024.05.11 |
SEO - meta tag (og:description, description 차이점) (3) | 2024.01.05 |