동기/비동기 와 블로킹/논블로킹 이 두 개념은 표현 형태는 비슷해 보일지라도, 서로 다른 차원에서 작업의 수행 방식을 설명하는 개념이다.
동기/비동기는 요청한 작업에 대해 완료 여부를 신경 써서 작업을 순차적으로 수행할지 아닌지에 대한 관점이고,블로킹/논블록킹은 현재 작업이 block(차단, 대기) 되느냐 아니냐에 따라 다른 작업을 수행할 수 있는지에 대한 관점이다.
- 대표적으로 JS의 setTimeout() 함수를 일반적으로 비동기 함수라고만 부르지만 동시에 논블로킹 함수이기도 하다. 즉, JS의 비동기 함수는 “비동기 + 논블로킹 함수”인 것이다.
*논블로킹 : 현재 작업이 차단 되지 않는다.
- 순차적으로 코드를 실행하는 것
- 특정 작업을 다른 작업과 관계없이 독립적으로 동작하게 만드는 것
- 실행 순서와 완료 순서가 일치하지 않다.
- ex) setTimeout(), fetch() 함수
- 동기는 작업 B가 완료되어야 다음 작업을 수행하고, 비동기는 작업 B의 완료 여부를 따지지 않고 바로 다음 작업을 수행한다.
- 자바스크립트의 setTimeout이나 fetch 와 같은 비동기 자바스크립트 코드를 브라우저 Web APIs에게 맡기고 → 백그라운드 작업이 끝난 결과를 콜백 함수 형태로 큐(Callback Queue)에 넣고 → 콜 스택이 비어 있으면 이벤트루프를 통해 호출 스택에 넣어 마무리 작업을 진행함
힙
- 변수, 상수들의 사용되는 메모리를 저장하는 영역
- 동적으로 생성된 자바스크립트 객체가 저장되는 공간
콜 스택
- 작성한 코드의 실행에 따라서 호출 스택에 쌓음
- 자바스크립트 엔진이 코드 실행을 위해 사용하는 메모리 구조
Web API
- 브라우저에서 제공하는 API 모음으로, 비동기적으로 실행되는 작업들을 전담하여 처리한다. (AJAX 호출, setimeout() 타이머 함수, DOM 조작 등)
Callback Queue
- 비동기적 작업이 완료되면 실행되는 함수들이 대기하는 공간
Event Loop
- 비동기 함수들을 적절한 시점에 실행시키는 관리자
Event Table
- 특정 이벤트(timeout, click, mouse 등)가 발생했을 때 어떤 callback 함수가 호출되야 하는지를 알고 있는 자료구조 (위 그림에는 없음)
Callback Queue에는 (macro)task queue와 microtask queue 두 가지 종류가 있다.
(macro)Task Queue
: setTimeout, setInterval, fetch, addEventListener 와 같이 비동기로 처리되는 함수들의 콜백 함수가 들어가는 큐 (macrotask queue 는 보통 task queue 라고 부름)
Microtask Queue
: promise.then, process.nextTick, MutationObserver 와 같이 우선적으로 비동기로 처리되는 함수들의 콜백 함수가 들어가는 큐 (처리 우선순위가 높음)
- Callback Queue의 종류에 따라 이벤트 루프가 콜 스택으로 옮기는 순서가 달라진다.
- 일반적으로 microtask queue가 가장 우선순위가 높아 먼저 microtask queue를 처리하여 먼저 비우고, 그 다음 task queue의 콜백을 처리한다.
- 전역 객체 콜 스택에 쌓이고
- asynceAdd()가 콜 스택에 쌓임
- asyncAdd 함수 바디에서 setTimeout()와 콜백 함수 cb()가 콜 스택에 담김
- 또한, JS는 비동기 함수(setTimeout())를 Web APIS에 넣김
- 그 다음은 asynceAdd()가 실행을 다 마쳐서 콜 스택에서 제거됨
- 다음에 setTimeout()을 실행하여 3초 후 Web APIs에서 제거되고, 콜백 함수인 cb() 함수가 콜백 Queue에 옮겨지게된다.
- Event Loop에 의해서 콜 스택으로 다시 옮겨진다.
- 결과값 4를 출력하게됨 모두 수행이 끝났기 때문에 콜 스택에 있는 것들은 제거 된다.
function bar() {
setTimeout(() => {
console.log("Second")
}, 500);
}
function foo() {
console.log("First");
}
function baz() {
console.log("Third");
}
bar();
foo();
baz();
- bar() 함수가 호출되고 그안의setTimeout() 함수가 호출되어 스택에 쌓인다.
- setTimeout() 함수의 매개변수에 할당된 콜백 함수를 Timer Web API에 전달한다. 그리고 Timer Web API 에서는 백그라운드로 500 밀리초를 셈한다.
- 다음foo() 함수가 호출되고 콘솔창(output)에 "First" 가 출력된다.이때 500 밀리초 대기 시간이 만료되면서, 이벤트 루프는Timer Web API에서 가지고 있던 콜백 함수를 Task Queue 로 옮긴다.
- 그다음baz() 함수가 호출되고 콘솔창에 "Third" 가 출력된다.
- 스택에 있는 모든 메인 자바스크립트 코드가 실행 완료 되어 Call Stack이 비워지게 된다.
- 이벤트 루프는 Call Stack 이 비어있는 경우를 탐지하여, Task Queue 에 있는 콜백 함수를 Call Stack 으로 옮긴다.
- Call Stack 에서 콜백 함수 코드를 실행하게 되고 콜솔창에는 "Second" 가 출력된다.