Javascript
[JavaScript] 자바스크립트 | 비동기 처리의 시작 콜백 이해하기, 콜백 지옥 체험 | JavaScript Callback
@leem
2025. 3. 26. 14:28
'use strict';
// JavaScript is synchronous.
// Execute the code block by order after hoisting.
// hoisting: var, function declaration
// (자바스크립트는 기본적으로 동기적이며, 호이스팅 이후 코드 순서대로 실행됨)
// (hoisting: 변수와 함수 선언이 코드 맨 위로 끌어올려지는 현상)
console.log('1');
setTimeout(() => console.log('2'), 1000);
// (1초 뒤 '2'를 비동기로 출력)
console.log('3');
// (먼저 '1', '3' 출력 후, 1초 뒤에 '2' 출력)
// Synchronous callback
// (동기 콜백 함수)
function printImmediately(print) {
print();
}
printImmediately(() => console.log('hello'));
// ('hello'가 즉시 출력됨)
// Asynchronous callback
// (비동기 콜백 함수)
function printWithDelay(print, timeout) {
setTimeout(print, timeout);
}
printWithDelay(() => console.log('async callback'), 2000);
// (2초 뒤 'async callback' 출력)
// Callback Hell example
// (콜백 지옥 예제)
class UserStorage {
loginUser(id, password, onSuccess, onError) {
setTimeout(() => {
if (
(id === 'ellie' && password === 'dream') ||
(id === 'coder' && password === 'academy')
) {
onSuccess(id);
// (로그인 성공 시 onSuccess 콜백 호출)
} else {
onError(new Error('not found'));
// (로그인 실패 시 onError 콜백 호출)
}
}, 2000); // (2초 후 로그인 처리)
}
getRoles(user, onSuccess, onError) {
setTimeout(() => {
if (user === 'ellie') {
onSuccess({ name: 'ellie', role: 'admin' });
// (권한 확인 성공 시 onSuccess 콜백 호출)
} else {
onError(new Error('no access'));
// (권한이 없으면 onError 콜백 호출)
}
}, 1000); // (1초 후 권한 확인)
}
}
const userStorage = new UserStorage();
const id = prompt('enter your id');
// (사용자 ID 입력 받음)
const password = prompt('enter your password');
// (사용자 비밀번호 입력 받음)
userStorage.loginUser(
id,
password,
user => {
userStorage.getRoles(
user,
userWithRole => {
alert(
`Hello ${userWithRole.name}, you have a ${userWithRole.role} role`
);
// (성공 시 사용자 역할을 alert로 출력)
},
error => {
console.log(error);
// (권한 조회 실패 시 오류 출력)
}
);
},
error => {
console.log(error);
// (로그인 실패 시 오류 출력)
}
);
동기와 비동기 (Synchronous vs Asynchronous)
자바스크립트는 기본적으로 동기적(synchronous)이다
개념적으로 JavaScript 는 한 줄씩 순차적으로 실행됩니다.
console.log('1');
setTimeout(() => console.log('2'), 1000);
console.log('3');
결과:
1
3
(1초 후)
2
🧾 실행 순서
- '1' 출력
- setTimeout 등록 → 1초 뒤에 실행하도록 예약
- '3' 출력
- 1초가 지나면 '2' 출력
📌 왜 이런 순서가 될까?
- 자바스크립트는 기본적으로 동기적입니다. 즉, 한 줄씩 순서대로 실행합니다.
- 하지만 setTimeout()과 같은 함수는 비동기 처리로 예약됩니다.
- 따라서 '1', '3'이 먼저 출력되고, '2'는 1초 뒤에 비동기로 출력됩니다.
콜백 함수 (Callback Function)
콜백 함수는 다른 함수에 인자로 전달되어 나중에 호출되는 함수입니다.
동기 콜백
function printImmediately(print) {
print();
}
printImmediately(() => console.log('hello'));
- printImmediately는 전달받은 print 함수를 즉시(synchronous) 실행합니다.
- 결과: 'hello'가 바로 출력됨.
비동기 콜백
function printWithDelay(print, timeout) {
setTimeout(print, timeout);
}
printWithDelay(() => console.log('async callback'), 2000);
- printWithDelay는 전달받은 print 함수를 지정된 시간 후 비동기적으로 실행합니다.
- 결과: 2초 후 'async callback' 출력
콜백 지옥 (Callback Hell)
복잡한 비동기 작업을 콜백 함수 안에 또 콜백 함수를 넣는 방식으로 처리할 경우, 코드가 지저분하고 읽기 어렵게 됩니다.
📌 문제점은?
- 콜백 안에 콜백이 중첩되면서 코드가 오른쪽으로 점점 밀림 → 😱 가독성 저하
- 하나라도 실수하거나 빠뜨리면 전체 흐름이 망가짐
- 유닛 테스트(부분 테스트)가 어려움 → 각각의 단계가 함수 내부 깊숙이 있어서 테스트 불가능
- 에러 추적이 어려움 → 어느 단계에서 실패했는지 파악 힘듦
정리
비동기 | 특정 작업이 완료된 뒤 실행되도록 예약됨 (setTimeout, API 호출 등) |
콜백 함수 | 나중에 실행되도록 함수에 전달된 함수 |
콜백 지옥 | 콜백 안에 콜백이 반복되어 코드가 복잡해지는 현상 |
동기 | 코드가 위에서 아래로 순서대로 실행됨 |