비동기 처리 (Async processing)
자바스크립트는 싱글 스레드 기반 언어
이기 때문에, 기본적으로 하나의 작업이 끝난 후 다음 작업이 실행되는 동기 방식
으로 동작한다. 하지만 브라우저나 Node.js 환경은 이벤트 루프와 비동기 API를 활용해 멀티 스레드 기반의 비동기 처리를 지원한다. 즉, 자바스크립트 자체는 싱글 스레드이지만, 비동기 처리를 통해 동시성을 구현할 수 있다.
동기 (Synchronous)
자바스크립트는 동기 방식
으로 동작한다. 즉, 하나의 작업이 끝난 후에야 다음 작업이 실행되는 블로킹 방식이다. 만약, 모든 작업을 동기적으로 처리하면 이미지나 데이터를 불러오는 동안 버튼 클릭이나 키보드 입력조차 반응하지 않는 상황이 발생할 수 있다. 이러한 경우 사용자는 웹사이트가 멈춘 것처럼 느끼게 된다. 따라서 오래 걸리는 작업은 비동기적 방식
으로 처리해야 사용자 경험을 해치지 않으면서 전체 성능도 향상시킬 수 있다.
less
동기 처리 흐름
└── 작업 A 시작
└── 작업 A 완료
└── 작업 B 시작
└── 작업 B 완료
└── 작업 C 시작
└── 작업 C 완료
동기적 처리와 블로킹 방식 예시
js
// 각 함수가 작업에 걸리는 시간이 각각 5초, 3초, 10초 라고 가정
const workA = () => {
//5초
console.log("workA");
};
const workB = () => {
//3초
console.log("workB");
};
const workC = () => {
//10초
console.log("workC");
};
workA();
workB();
workC();
- 위 코드는 작업이 순차적으로 실행되기 때문에, 총 18초가 걸리게 된다. 같은 작업을 비동기적으로 처리한다면, 가장 오래 걸리는 작업 시간인 10초만 소요된다.
비동기 (Asynchronous)
비동기는 하나의 스레드에서 여러 작업을 동시에 처리할 수 있는 방식이다. 이러한 방식은 논 블로킹 방식
이라고도 한다. 이전 작업이 끝날 때까지 기다리지 않고, 다음 작업을 먼저 실행한 뒤, 이전 작업의 결과는 나중에 콜백이나 이벤트 루프를 통해 처리된다. 자바스크립트는 싱글 스레드 기반이지만, 이벤트 루프와 비동기 API를 통해 이러한 비동기 처리를 가능하게 만든다.
less
비동기 처리 흐름
├── 작업 A 시작 (3초 후 완료 예정)
│ └── 콜백 대기
├── 작업 B 시작 (1초 후 완료 예정)
│ └── 콜백 대기
├── 작업 C 시작 (2초 후 완료 예정)
│ └── 콜백 대기
└── 완료 순서
├── 작업 B 완료 → 콜백 실행
├── 작업 C 완료 → 콜백 실행
└── 작업 A 완료 → 콜백 실행
setTimeout()
js
setTimeout((callback) => {}, delay);
setTimeout()
은 자바스크립트의 비동기 처리에 사용되는 내장 함수이다.setTimeout()
은 두 개의 인자를 받는다:- callback: 나중에 실행할 함수
- delay: 몇 밀리초(ms) 뒤에 콜백을 실행할지 지정 (1초는 1000, 3초는 3000)
js
setTimeout(() => {
console.log("3초만 기다리세요");
}, 3000);
// 3초만 기다리세요
js
setTimeout(() => {
console.log("3초만 기다리세요");
}, 3000);
console.log("종료");
// 종료
// 3초만 기다리세요
setTimeout()
은 지정한 시간(여기선 3초)이 지난 후에 콜백 함수를 한 번만 실행한다.- setTimeout 안의 코드는 비동기적으로 처리되기 때문에, 아래에 있는
console.log("종료")
가 먼저 실행된다. - 민약, 종료라는 문자열을 3초 뒤에 출력하고 싶다면, 해당 코드를 콜백함수 내부에 작성해야 한다.
js
setTimeout(() => {
console.log("종료");
console.log("3초만 기다리세요");
}, 3000);
// 종료
// 3초만 기다리세요
setTimeout()
안에서 두 작업을 순차적으로 실행하며, 3초 후에 두 줄이 연달아 실행된다.
js
const work = (callback) => {
setTimeout(() => {
console.log("3초만 기다리세요");
callback();
}, 3000);
};
work(() => {
console.log("종료");
});
// 3초만 기다리세요
// 종료
- 콜백 함수 분리를 통해 흐름을 제어하는 방식
console.log("종료");
를 콜백 함수로 만들어work
라는 비동기 함수에 인자로 전달한다.work
함수 내부에서 setTimeout을 통해 3초 뒤 비동기 작업을 수행한 후, 전달한 콜백 함수가 실행한다. 이로 인해 "3초만 기다리세요"가 먼저 출력된 뒤, 콜백 함수 내부의 "종료"가 출력된다.- 이러한 방식에서 콜백이 여러 단계로 중첩되기 시작하면, 코드가 복잡해지고 가독성이 떨어지는 콜백 헬(callback hell)이 발생하게 된다. 이 문제는 Promise를 사용하여 더 명확하고 체계적으로 비동기 흐름을 관리함으로써 해결할 수 있다.