42장. 비동기 프로그래밍
42-1. 동기 처리와 비동기 처리
- JS 엔진은 단 하나의 실행 컨텍스트 스택을 가진다.
- 동시에 2개 이상의 함수를 실행할 수 없다는 것을 의미한다.
- JS 엔진은 한 번에 하나의 태스크만 실행할 수 있는 싱글 스레드 방식으로 동작한다.
- 싱글 스레드 방식에서 처리에 시간이 걸리는 태스크를 실행하는 경우 블로킹이 발생한다.
- 현재 실행 중인 태스크가 종료할 때까지 다음에 실행될 태스크가 대기하는 방식을 synchronous 처리
- 현재 실행 중인 태스크가 종료되지 않은 상태라도 다음 태스크를 곧바로 실행하는 방식을 asynchronous 처리
- setTimeout, setInterval, HTTP 요청, 이벤트 핸들러는 비동기 처리 방식으로 동작한다.
42-2. 이벤트 루프와 태스크 큐
- 싱글 스레드 방식인데 브라우저가 동작하는 것을 보면 많은 태스크가 동시에 처리되는 것 처럼 느껴진다.
- JS의 동시성(concurrency)을 지원하는 것이 이벤트 루프(event loop)다.
- 이벤트 루프는 브라우저에 내장되어 있는 기능 중 하나다.
- 싱글 스레드 방식으로 동작하는 것은 JS 엔진이지 브라우저가 아니다.
// 예제로 알아보는 흐름
function foo() {
console.log('foo');
}
function bar() {
console.log('bar');
}
setTimeout(foo, 0);
bar();
- 전역 코드 평가 → 전역 실행 컨텍스트 생성 → 콜 스택에 푸시됨.
- setTimeout() 호출 → 함수 실행 컨텍스트 생성되고 콜 스택에 푸시됨.
- setTimeout() 실행되면 콜백 함수를 호출 스케줄링하고 종료 → 콜 스택에서 팝됨. 여기서 타이머 설정과 타이머 만료되면 콜백 함수를 태스크 큐에 푸시하는 것은 브라우저의 역할임.
- 아래 두 과정은 병행 처리됨.
- 브라우저가 타이머 설정 → 타이머 만료 → 콜백함수 foo()가 태스크 큐에 푸시됨. 여기서 지연 시간 이후에 콜백 함수가 태스크 큐에 푸시되어 대기하지만 콜 스택이 비어야 호출되므로 정확한 시간을 보장하진 않음.
- bar() 호출 → 함수 실행 컨텍스트 생성되고 콜 스택에 푸시됨. → bar() 종료 → 콜 스택에서 팝됨 → 타이머가 만료되었다면 foo() 가 태스크큐에서 대기중임.
- 전역 코드 실행 종료 → 전역 실행 컨텍스트 콜 스택에서 팝됨 → 콜 스택에는 아무런 실행 컨텍스트 존재하지 않음.
- 이벤트루프가 콜 스택이 비어있는지 확인 → 태스크 큐에서 대기중인 foo() 를 콜 스택에 푸시함 → 콜백함수 foo() 의 함수 실행 컨텍스트가 생성되고 콜 스택에 푸시됨. → foo() 종료되고 콜 스택에서 팝됨.
텍스트만 보는것 보다는 책에서 이미지랑 같이 보는게 이해하기 더 쉬울듯.