동기 vs 비동기

동기(Synchronous)는 '동시에 발생하는'의 뜻이다. 프로그래밍에서는 요청과 응답이 동시에 발생하는 뜻으로 생각할 수 있는데, 요청을 하면 응답이 바로 그 자리에서 동시에 일어나야 한다. 동기적인 코드에서는 코드 작성 순서 대로 실행 순서를 보장 받을 수 있다. 1번 요청 코드의 응답이 완료 되면 2번 요청으로 넘어갈 수 있다.

반대로 비동기(Asynchronous)는 '동시에 발생하지 않는'의 뜻이다. 프로그래밍에서는 요청과 응답이 동시에 발생하지 않는 뜻으로 생각할 수 있고, 요청을 하고 응답이 바로 그 자리에서 일어나지 않을 수 있다. 비동기적인 코드에서는 코드 작성 순서와 실행 순서는 보통 일치하지 않는다. 1번 요청 코드를 응답을 기다리면서 2번 요청의 응답을 기다릴 수 있다.

자바스크립트는 싱글 스레드 언어이기 때문에 한 번에 한 가지 일만을 처리한다. 동기적인 것이다. 하지만 우리는 브라우저에서 동시 다발적으로 처리되는, 바로 비동기적인 일들을 경험한다. 어떻게 그럴 수 있을까?

이벤트 루프

자바스크립트의 비동기가 가능한 이유는 바로 브라우저에서 지원하는 이벤트 루프 덕분이다. 자바스크립트는 싱글 스레드이지만 이벤트 루프로 인하여 멀티 스레드처럼 보이는 것이다.

이벤트 루프가 하는 일은 간단하다. 콜 스택과 콜백 큐를 감시한다. 콜 스택이 비었다면 콜백 큐에서 첫 번째 작업을 가져와 콜 스택에 푸쉬해서 그 작업을 실행하게 만든다.

console.log('Hi');
setTimeout(function cb1() { 
    console.log('cb1');
}, 5000);
console.log('Bye');

console.log('Hi')console.log('Bye')는 호출하면 바로 콜 스택에 쌓이고 바로 실행된다. 이와 달리 setTimeout(cb1)은 호출되고 콜 스택에 쌓인 후에 실행되면서 브라우저의 Web API인 타이머를 만든다. setTimeout(cb1)은 실행되었기 때문에 콜 스택에서 사라진다. 5000ms가 지나고 나서 타이머는 완료되고 cb1 콜백을 콜백 큐에 푸쉬한다. 이때 이벤트 루프는 콜 스택이 빈 것을 확인하고 콜백 큐에 있던 cb1을 콜 스택에 푸쉬한다. cb1이 실행되면서 console.log('cb1')을 콜 스택에 쌓는다. 그리고 console.log('cb1')이 실행된다.


도움이 된 자료

JavaScript Asynchronous Programming and Callbacks, (2022.03.28), https://nodejs.dev/learn/javascript-asynchronous-programming-and-callbacks

How JavaScript works: Event loop and the rise of Async programming + 5 ways to better coding with async/await, (2022.03.28), https://blog.sessionstack.com/how-javascript-works-event-loop-and-the-rise-of-async-programming-5-ways-to-better-coding-with-2f077c4438b5