비동기 함수와 콜백함수의 관계
목차
⚙️ 비동기 함수와 콜백 함수의 관계
자바스크립트는 싱글 스레드 기반 언어지만,
비동기(Asynchronous) 방식을 통해 동시에 여러 작업을 수행하는 것처럼 동작할 수 있다.
이때, 비동기 작업이 완료된 **“이후 시점에 실행할 코드”**를 등록하기 위해 사용하는 것이 바로 콜백 함수(callback function) 이다.
🔹 1. 비동기 함수의 기본 개념
비동기 함수는 실행 즉시 결과를 반환하지 않는다.
예를 들어, 서버에 데이터를 요청하면 응답이 오기 전까지 시간이 걸리기 때문이다.
그동안 자바스크립트는 다른 코드들을 먼저 실행시키고,
응답이 도착하면 콜백 함수를 통해 결과를 처리한다.
console.log("요청 시작");
setTimeout(() => {
console.log("응답 도착");
}, 2000);
console.log("다른 작업 실행 중...");출력 결과:
요청 시작
다른 작업 실행 중...
응답 도착📌 즉:
비동기 함수는 작업을 백그라운드(Web API)로 넘기고,
작업이 끝나면 등록된 콜백을 다시 실행시킨다.
🔹 2. 비동기 작업을 “순차적으로” 다뤄야 할 때
비동기 함수는 기본적으로 순서를 보장하지 않는다.
하지만 실제 개발에서는 “이 작업이 끝난 후 다음 작업을 실행해야 하는 경우”가 많다.
예를 들어 👇
getUser((user) => {
getPosts(user.id, (posts) => {
getComments(posts[0].id, (comments) => {
console.log(comments);
});
});
});여기서
getUser→ 사용자 정보 요청getPosts→ 해당 사용자의 게시글 요청getComments→ 게시글의 댓글 요청
이 순서대로 실행되어야 하는 의존 관계가 있다.
하지만 이걸 비동기 함수로 다루려면 콜백을 중첩해야 해서
코드가 점점 오른쪽으로 밀리는 콜백 지옥(callback hell) 구조가 된다.
🔹 3. 콜백 지옥(Callback Hell)
비동기 작업이 많아질수록 콜백 안에 콜백을 넣게 되며,
결국 아래처럼 복잡한 형태로 변한다 👇
loginUser(user, (res1) => {
getProfile(res1.id, (res2) => {
updateProfile(res2.id, (res3) => {
sendNotification(res3.id, (res4) => {
console.log("모든 작업 완료");
});
});
});
});이런 구조는 다음과 같은 문제를 만든다:
| 문제 | 설명 |
|---|---|
| 가독성 저하 | 코드가 중첩되어 한눈에 흐름 파악이 어려움 |
| 에러 처리 어려움 | try-catch를 사용하기 어려움 |
| 유지보수 불편 | 한 단계만 수정해도 전체 체인을 건드려야 함 |
🔹 4. 콜백의 핵심 요약
| 개념 | 설명 |
|---|---|
| 콜백 함수 | 비동기 작업이 끝난 뒤 실행할 함수를 등록 |
| 콜백의 목적 | 코드 실행 순서를 제어하기 위함 |
| 콜백 지옥 | 비동기 작업이 많아질수록 중첩이 심해지는 문제 |
| 해결 방향 | 이후 등장한 Promise 와 async/await 가 콜백을 더 쉽게 다루도록 함 |
💡 정리
비동기 함수는 **“언제 끝날지 모르는 작업”**을 처리하기 위한 구조이고,
콜백 함수는 그 작업이 끝난 후 실행할 로직을 등록하는 방식이다.
하지만 콜백만으로 여러 작업을 순차 처리하면 콜백 지옥이 생긴다.
그래서 이후에 등장한 Promise와 async/await은 이 콜백 제어를 더 깔끔하게 만든 발전된 형태다.