- Published on
이벤트 루프, V8 엔진, 그리고 스택 & 큐
- Authors
- Name
- Hyo814
Q1. V8 엔진의 주요 역할은 무엇인가요?
답변: V8 엔진은 자바스크립트 코드를 빠르게 실행하기 위해 설계된 고성능 엔진입니다. 자바스크립트 코드를 먼저 파싱하여 AST(Abstract Syntax Tree)를 생성한 후, 바이트코드와 네이티브 코드로 변환합니다. 특히 JIT(Just-In-Time) 컴파일을 통해 자주 실행되는 코드를 최적화하여 빠르게 처리하며, 메모리 관리를 위해 가비지 컬렉션을 수행합니다.
Q2. 이벤트 루프(Event Loop)의 역할과 구조를 설명하세요.
답변: 이벤트 루프는 자바스크립트의 비동기 작업을 처리하는 핵심 메커니즘입니다.
- 콜스택(Call Stack): 함수 실행 컨텍스트가 쌓이는 구조로, 동기적으로 코드를 실행합니다.
- 테스크 큐(Task Queue): 비동기 작업(예:
setTimeout
, I/O 작업)의 콜백이 대기하는 큐입니다. - 마이크로태스크 큐(Microtask Queue):
Promise
의then
이나MutationObserver
같은 작업이 처리되는 더 높은 우선순위의 큐입니다.
이벤트 루프는 콜스택이 비어 있는 상태에서 태스크 큐의 작업을 순차적으로 실행합니다. 마이크로태스크는 일반 태스크보다 우선 처리됩니다.
Q3. 이벤트 루프에서 마이크로태스크와 테스크의 차이점은 무엇인가요?
답변:
- 마이크로태스크(Microtask):
Promise.then
,async/await
의 결과 처리,MutationObserver
가 포함됩니다.- 우선순위가 높아 콜스택이 비어 있을 때 바로 실행됩니다.
- 테스크(Task):
setTimeout
,setInterval
, DOM 이벤트 처리 등이 포함됩니다.- 마이크로태스크가 모두 처리된 후에 실행됩니다.
Q4. 왜 이벤트 루프는 콜스택과 큐를 사용하나요?
답변: 콜스택은 함수 호출과 실행을 관리하기 위해 사용되고, 큐는 비동기 작업을 처리하기 위해 사용됩니다. 자바스크립트는 싱글 스레드로 동작하기 때문에, 이벤트 루프를 통해 비동기 작업의 순서를 조정하고 처리할 수 있습니다. 이를 통해 UI가 멈추지 않고 비동기 처리가 가능합니다.
**2. 기술 노트 **
기술 노트 1: V8 엔진 구조
1. **코드 파싱**: 자바스크립트 코드를 AST로 변환
2. **바이트코드 생성**: 인터프리터(Ignition)가 실행
3. **최적화된 네이티브 코드**: JIT 컴파일러(Turbofan)가 생성
4. **메모리 관리**: 가비지 컬렉션(정리되지 않은 메모리 해제)
5. **콜스택 관리**: 실행 중인 함수와 컨텍스트를 추적
기술 노트 2: 이벤트 루프 단계
1. **콜스택(Call Stack)**:
- 현재 실행 중인 함수가 쌓이고 처리됨.
2. **테스크 큐(Task Queue)**:
- 타이머, I/O 작업 완료 후 실행될 콜백이 대기.
- `setTimeout`, `setInterval` 등이 포함.
3. **마이크로태스크 큐(Microtask Queue)**:
- 더 높은 우선순위를 가짐.
- `Promise.then`, `MutationObserver` 등이 포함.
4. **우선순위**:
- 콜스택 비우기 → 마이크로태스크 처리 → 테스크 처리.
기술 노트 3: 이벤트 루프의 동작 예시
console.log('Start')
setTimeout(() => {
console.log('Task Queue')
}, 0)
Promise.resolve().then(() => {
console.log('Microtask Queue')
})
console.log('End')
// 출력 순서:
// Start
// End
// Microtask Queue
// Task Queue
**기술 노트 4
// 이벤트 예제: 이벤트, target, currentTarget, 이벤트 리스너, 이벤트 전파, 이벤트 위임
// 1. 버튼 클릭 이벤트 예제
document.querySelector('#myButton').addEventListener('click', function () {
console.log('Button clicked!')
})
// 2. 이벤트 타겟 (event.target) 예제
document.querySelector('#parent').addEventListener('click', function (event) {
console.log('Target:', event.target) // 실제 클릭된 요소
})
// 3. 커렌트 타겟 (event.currentTarget) 예제
document.querySelector('#parent').addEventListener('click', function (event) {
console.log('Current Target:', event.currentTarget) // 이벤트 핸들러가 연결된 요소
})
// 4. 이벤트 타겟과 커렌트 타겟 비교
document.querySelector('#parent').addEventListener('click', function (event) {
console.log('Target:', event.target) // 클릭된 실제 요소
console.log('Current Target:', event.currentTarget) // 이벤트 핸들러가 연결된 요소
})
// 5. 이벤트 위임 예제
document.querySelector('#list').addEventListener('click', function (event) {
if (event.target.tagName === 'LI') {
console.log('Clicked item:', event.target.textContent)
}
})
// 6. 이벤트 전파 단계: 캡처링(Capturing)과 버블링(Bubbling)
// 이벤트 전파 단계
// - 캡처링 단계: 이벤트가 최상위 요소에서부터 이벤트가 발생한 요소로 내려옴
// - 타깃 단계: 이벤트가 발생한 요소에 도달
// - 버블링 단계: 이벤트가 다시 상위 요소로 올라감
document.querySelector('#child').addEventListener(
'click',
function (event) {
console.log('Child clicked - Bubbling')
},
false
) // 버블링 단계 (default)
document.querySelector('#parent').addEventListener(
'click',
function (event) {
console.log('Parent clicked - Capturing')
},
true
) // 캡처링 단계
// 7. 이벤트 전파 중단: stopPropagation()
document.querySelector('#child').addEventListener('click', function (event) {
console.log('Stopping propagation')
event.stopPropagation() // 부모로 전파 중단
})
document.querySelector('#parent').addEventListener('click', function (event) {
console.log('Parent clicked (will not log if propagation is stopped)')
})
// 8. preventDefault() 사용 예제
document.querySelector('#link').addEventListener('click', function (event) {
event.preventDefault() // 기본 동작(예: 링크 이동)을 막음
console.log('Default action prevented')
})
// 이벤트 루프와 관련된 예제
// 기본적인 이벤트 루프 동작 예제
console.log('Start')
setTimeout(() => {
console.log('Task from setTimeout')
}, 0)
Promise.resolve().then(() => {
console.log('Microtask from Promise')
})
console.log('End')
// 실행 순서 설명:
// 1. console.log("Start") 실행
// 2. setTimeout의 콜백은 테스크 큐(Task Queue)로 이동
// 3. Promise.then의 콜백은 마이크로태스크 큐(Microtask Queue)로 이동
// 4. console.log("End") 실행
// 5. 마이크로태스크 큐의 작업 실행 ("Microtask from Promise")
// 6. 테스크 큐의 작업 실행 ("Task from setTimeout")
// 마이크로태스크 우선 처리 예제
console.log('Start')
setTimeout(() => {
console.log('Task from setTimeout')
}, 0)
Promise.resolve()
.then(() => {
console.log('Microtask 1 from Promise')
})
.then(() => {
console.log('Microtask 2 from Promise')
})
console.log('End')
// 실행 순서 설명:
// 1. console.log("Start") 실행
// 2. setTimeout의 콜백은 테스크 큐(Task Queue)로 이동
// 3. 첫 번째 Promise.then의 콜백은 마이크로태스크 큐(Microtask Queue)로 이동
// 4. console.log("End") 실행
// 5. 마이크로태스크 큐 작업 실행 ("Microtask 1 from Promise" -> "Microtask 2 from Promise")
// 6. 테스크 큐 작업 실행 ("Task from setTimeout")