문맥 교환이란?
현재까지의 작업 상태나 다음 작업에 필요한 각종 데이터를 저장하고 읽어오는 작업
하나의 프로세스가 CPU를 사용중인 상태에서 다른 프로세스가 CPU를 사용하도록 하기 위해, 이 전의 프로세스의 상태를 보관하고 새로운 프로세스의 상태를 적재하는 작업
자바스크립트는 싱글 스레드 언어라고 알려져있다. 그러나 보통 싱글 스레드라고 하면 한번에 하나의 작업만 수행할 수 있다고 알고 있는데, 자바스크립트는 어떻게 한번에 여러 요청을 받을 수 있을까?
결론부터 말하자면 싱글 스레드가 맞다. 자바스크립트의 메인 스레드인 이벤트 루프가 싱글 스레드이기 때문에 자바스크립트는 싱글 스레드 언어라고 부른다. 하지만 이벤트 루프만 독립적으로 실행되지 않고 웹 브라우저나 NodeJs와 같은 멀티 스레드 환경에서 실행된다. 즉, 자바스크립트 자체는 싱글 스레드가 맞지만, 자바스크립트 런타임은 싱글 스레드가 아니라고 할 수 있다.
자바스크립트는 원래 웹페이지의 보조적인 기능을 수행하려고 만들어진 언어이다. 멀티 스레드인 자바는 다소 무겁고 어렵다는 인식이 있고, 동시성 문제가 존재하다보니, 복잡한 시나리오를 신경 쓸 필요가 없는 싱글 스레드 형식이 채택되었었다.
실제로 구글 Chrome 브라우저는 기존 웹 페이지에서 동시성 문제를 일으킬 수 있다는 이유로 단일 웹 사이트 페이지의 자바스크립트 코드가 동시에 실행되는 것을 허용하지 않는다.
기존 동기식 요청은 코드 한줄씩 차례대로 실행했다. 그래서 하나의 작업에 걸리는 시간에 관계없이 첫번째 코드가 실행된 뒤 다음 코드가 실행됐다. 이렇게 되면 앞의 작업시간이 길수록 시간의 낭비가 심해진다. 이러한 문제는 하나의 요청이 완료될 때까지 기다리지 않고 동시에 다른 작업을 실행하는 비동기 호출로 극복할 수 있다.
자바스크립트가 비동기 코드를 어떻게 동작시키는지 알아보기 위해선 자바스크립트의 런타임 환경에 대해 알아야 한다. 자바스크립트가 실행될 때는 다음과 같은 요소들이 실행을 도와준다.
- Call Stack : 자바스크립트에서 수행해야 할 함수들을 순차적으로 스텍에 담아 처리
- Web API : 웹 브라우저에서 제공하는 API로 AJAX나 Timeout등 비동기 작업을 실행
- Task Queue : Callback Queue라고도 하며 Web API에서 넘겨받은 Callback 함수를 저장
- Event Loop : Call Stack이 비어있다면 Task Queue의 작업을 Call Stack으로 옮김
실제 비동기 코드는 이런 식으로 앞선 설명처럼 이렇게 동작하게 된다.
console.log("처음 실행");
setTimeout(() => console.log("두번째 실행?"), 0);
console.log("세번째 실행?");
// 처음 실행
// 세번째 실행?
// 두번째 실행?
문자열이 출력된 순서를 보면 코드의 입력 순서와는 다르게 setTimeout()
안의 콘솔문의 출력이 마지막에 이루어진다.
console.log("처음 실행");
가 콜 스텍에 쌓이게 되고, 바로 실행되어 콜 스텍에서 제거된다. setTimeout(() => console.log("두번째 실행?"), 0);
이 콜 스텍에 쌓이게 되고, setTimeout()
과 같은 비동기 작업은 바로 실행되지 않고 콜 스텍에서 Web API로 넘어가게 되어 비동기 처리가 된 후 콜백 함수를 테스크 큐로 넘겨 순서를 기다린다.console.log("세번째 실행?");
가 콜 스텍에 쌓이게 되고, 바로 실행되어 콜 스텍에서 제거된다.setTimeout()
의 콜백 함수를 콜 스텍에 호출한다.