나의 착각
실제 개발을 하다보면, 비동기 함수들을 많이 사용하게 됩니다.
"Ajax"라던가, "타이머 API", "이벤트 리스너" 등.. 실무에서는 잘 사용하고 있지만,
그 개념에 대한 정립이 부족하다는 생각이 들었습니다.
비동기 함수의 동작 방식을 ... 시간이 오래 걸리는 작업을 백그라운드에서 처리하고,
해당 작업이 완료되면 처리되는 개념으로 이해했었습니다.
이것은 굉장히 모호한 생각이죠.
자바스크립트는 싱글 쓰레드이기 때문에, 한번에 한 가지 일만 수행할 수 있는데요.
동기적으로 작업이 오래 걸리면 다음 작업을 못하고 멈춰버리게 됩니다.
function a() {
for(let i=0; i<Math.pow(10,10); i++) {}
}
function b() {
console.log('end');
}
a();
b(); // a가 종료될 때까지 b는 계속 기다립니다. 이 두 함수는 동기적으로 동작하기 때문입니다.
이를 방지하기 위해서 논블로킹 형태로 처리되는 개념이 비동기라고 할 수 있습니다.
만약 위의 a, b 함수가 비동기 함수라면, a가 실행되고 나서 즉시 b가 실행됩니다.
그리고 작업이 완료되는 순서에 따라 a, b의 작업 완료 순서가 정해집니다.
(a -> b, 또는 b -> a 순서)
setTimeout 예시
setTimeout에 0초를 주고 실행하면 이것은 비동기 프로그래밍이 아닌 걸까요?
console.log(1);
setTimeout(() => {
console.log(2);
}, 0)
console.log(3);
위의 코드는 순차적으로 1, 2, 3을 콘솔에 찍을까요?
결과는 1, 3, 2 순서로 콘솔에 숫자가 찍힙니다.
이처럼 동기적으로 실행되는 함수가 있고, 비동기적으로 실행되는 함수 (또는 API)가 존재합니다.
자바스크립트에서 비동기적으로 작동하는 원리
자바스크립트는 비동기 방식으로 동작하는 API를 제공합니다.
대표적인 예로, Promise, Web API, 타이머 API, Ajax가 있습니다.
함수는 실행할 때마다, 호출 스택(Call Stack)에 함수 실행 컨텍스트를 넣습니다.
실행이 완료되면, 호출 스택에서 제거됩니다.
비동기 함수도 실행되면 호출 스택에 함수 실행 컨텍스트가 추가되고, 호출 스택에서 제거됩니다.
브라우저 환경에서 비동기 함수가 동작한다고 가정했을 때, 비동기 함수의 기능은 브라우저에서 수행합니다.
브라우저에서 비동기 작업을 마치면, 콜백 함수를 작업 큐(Task Queue)로 전달합니다.
( Promise 같은 경우에는 마이크로태스트 큐로 콜백함수를 전달합니다. )
브라우저에서 비동기 작업을 처리할 수 있기 때문에, 자바스크립트는 비동기 작업을 처리할 수 있는 것입니다.
브라우저 입장으로보면 자바스크립트 엔진도 하나의 쓰레드 (싱글 쓰레드)로 볼 수 있고, 비동기 작업은 다른 쓰레드에서 처리하는 것입니다. (멀티 쓰레드)
이벤트 루프는 호출 스택이 비었는지 체크하고, 테스크 큐에 있는 콜백 함수를 호출 스택으로 넣어줍니다.
콜백 함수가 실행될 때, 함수 실행 컨텍스트가 생성되고 완료되면 함수 실행 컨텍스트가 호출 스택에서 제거됩니다.
setTimeout 예시로 보는 비동기 원리
// 1번
console.log(1);
// 2번
setTimeout(() => {
console.log(2);
}, 0)
// 3번
console.log(3);
1) console.log(1)가 실행되면 호출 스택에 함수 실행 컨텍스트가 추가되었다가 제거됩니다.
2) setTimeout 함수가 실행되면, 호출 스택에 함수 실행 컨텍스트가 추가되었다가 제거됩니다.
3) 브라우저에서 타이머 동작을 수행하고, 0초가 지나면 작업 큐로 콜백 함수를 전달합니다.
4) console.log(3)이 실행되면, 호출 스택에 함수 실행 컨텍스트가 추가되었다가 제거됩니다.
5) 호출 스택이 비었으므로, 콜백 함수 (console.log(2)) 가 실행되고 함수 실행 컨텍스트가 추가되었다가 제거됩니다.
참고
https://www.youtube.com/watch?v=s1vpVCrT8f4 (드림코딩 엘리 유튜브)
'JavaScript' 카테고리의 다른 글
[Javascript] 쓰로틀링(throttle), 디바운싱(debounce)을 헷갈리지 말자! (0) | 2023.03.15 |
---|---|
[Javascript] 2차원 배열 만들기 + 2차원 배열 순회 (0) | 2022.10.15 |
[Javascript] 스코프 체인이란..? (0) | 2022.09.10 |
[Javascript] 함수 선언문과 함수 표현식 (0) | 2022.09.10 |
[Javascript] 배열 메소드 - forEach, map (순회 목적) (0) | 2022.07.31 |