함수가 실행되려면 “함수 코드 평가 과정”에서 생성된 함수 실행 컨텍스트가 실행 컨텍스트 스택에 푸시되어야 한다. 함수의 실행 순서는 실행 컨텍스트 스택으로 관리한다.
자바스크립트 엔진은 단 하나의 실행 컨텍스트 스택을 갖는다. 현재 실행 중인 함수가 종료하면 비로소 실행되기 시작한다. 이처럼 자바스크립트 엔진인 한 번에 하나의 태스크만 실행할 수 있는 싱글 스레드 방식으로 동작한다.
싱글 스레드 방식은 한 번에 하나의 태스크만 실행할 수 있기 때문에 처리에 시간이 걸리는 태스크를 실행하는 경우 블로킹(작업 중단)이 발생한다.
현재 실행 중인 태스크가 종료할 때까지 다음에 실행될 태스크가 대기하는 방식을 동기 처리라고 한다. 반면에 현재 실행 중인 태스크가 종료되지 않은 상태라 해도 다음 태스크를 곧바로 실행하는 방식을 비동기 처리라고 한다.
비동기 함수는 전통적으로 콜백 패턴을 사용하는데. 비동기 처리를 위한 콜백 패턴은 콜백 헬을 발생시켜 가독성을 나쁘게 하고 , 비동기 처리 중 발생한 에러의 예외처리가 곤란하기 때문에. 프로미스를 사용한다. → 이건 나중에 살펴보기로 하자.
앞서 자바스크립트의 특징 중 하나가 싱글 스레드 방식으로 하나의 태스크만 처리할 수 있다고 했는데, 브라우저가 동작하는 것을 살펴보면 많은 태스크가 동시에 처리되는 것처럼 느껴진다. 어떻게 이것이 이뤄질 수 있었을까?
이런 자바스크립트의 동시성을 지원하는 것은 바로 이벤트 루프다. 이벤트 루프는 브라우저에 내장되어있는 기능 중 하나다.
자바스크립트 엔진은 크게 2개의 영역으로 나눌 수 있다.
비동기 방식으로 동작하는 setTimeout의 콜백 함수의 평가와 실행은 자바스크립트 엔진이 담당하지만 호출 스케줄링을 위한 타이머 설정과 콜백 함수의 등록은 브라우저 또는 Node.js가 담당한다. 이를 위해 브라우저 환경은 태스크 큐와 이벤트 루프를 제공한다.
이처럼 비동기 함수인 setTimeout의 콜백 함수 foo()는 태스크 큐에 푸시뒤어 대기하다가 콜 스택이 비게 되면, 비로소 콜 스택에 푸시되어 실행된다. 자바스크립트는 싱글 스레드 방식으로 동작한다. 이때 싱글 스레드 방식으로 동작하는 것은 브라우저가 아니라 브라우저에 내장된 자바스크립트 엔진이라는 것에 주의하기 바란다. 즉, 자바스크립트 엔진은 싱글 스레드로 동작하지만 브라우저는 멀티 스레드로 동작한다.
<aside> 💡 브라우저는 자바스크립트 엔진 외에도 렌더링 엔진과 Web API를 제공한다. Web API는 브라우저에서 제공하는 API이며, DOM API와 타이머 함수, HTTP 요청과 같은 비동기 처리를 포함한다.
</aside>