JAVASCRIPT 콜백 지옥
콜백 지옥이란?
▶ 콜백 지옥(Callback Hell)은 JavaScript 코드에서 콜백 함수를 중첩해서 사용할 때 발생하는 코드의 가독성을 떨어뜨리고 유지보수를 어렵게 만드는 상황을 의미합니다. 콜백 지옥의 경우 비동기적인 작업을 처리할 때 많이 발생하는데 콜백 함수를 연속적으로 사용할 때 코드가 깊게 중첩되어 복잡해지기 때문입니다.
아래는 간단한 콜백 지옥의 예시입니다.
1
2
3
4
5
6
7
getUser(userId, function(user) {
getOrders(user, function(orders) {
getOrderDetails(orders[0], function(orderDetails) {
// 원하는 작업 수행
});
});
});
▶ 위 코드에서는 getUser, getOrders, getOrderDetails와 같은 비동기 함수들이 콜백 형태로 사용되고 있습니다.
이런 형태로 콜백이 계속 중첩되면 코드가 아래로 계속 들어가면서 가독성이 떨어지고, 오류를 찾기 어려워집니다.
콜백 지옥을 해결하는 방법
▶ 그렇다면 해결방법이 없을까? 아닙니다! 콜백 지옥을 해결하는 방법 아래에서 알려드릴게요.
1. 콜백 대신 프로미스(Promise) 사용
- 프로미스는 비동기 작업을 좀 더 구조적이고 순차적으로 처리할 수 있게 해주는 객체로 프로미스를 사용하여 콜백 지옥을 피할 수 있습니다. 아래의 예시를 통해 살펴볼게요.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
function getUser(userId) {
return new Promise((resolve, reject) => {
// 비동기 작업
setTimeout(() => {
const user = { id: userId, name: 'Alice' };
resolve(user);
}, 1000);
});
}
function getOrders(user) {
return new Promise((resolve, reject) => {
// 비동기 작업
setTimeout(() => {
const orders = [{ id: 1, product: 'Product A' }, { id: 2, product: 'Product B' }];
resolve(orders);
}, 1000);
});
}
function getOrderDetails(order) {
return new Promise((resolve, reject) => {
// 비동기 작업
setTimeout(() => {
const orderDetails = { id: order.id, total: 100 };
resolve(orderDetails);
}, 1000);
});
}
getUser(123)
.then(user => getOrders(user))
.then(orders => getOrderDetails(orders[0]))
.then(orderDetails => {
console.log(orderDetails); // { id: 1, total: 100 }
// 원하는 작업 수행
})
.catch(error => {
console.error(error); // 오류 처리
});
▶ 위의 예시는 프로미스를 사용하여 getUser, getOrders, getOrderDetails 함수들은 각각 프로미스를 반환하고, 이를 then 메서드로 연결하여 비동기 작업을 순차적으로 처리했습니다. 그리고 마지막에는 catch 메서드로 오류를 처리했습니다.
💡 추가 보충 설명
▶ return new Promise((resolve, reject) => { … })은 JavaScript에서 프로미스 객체를 생성하는 방법 중 하나입니다.
이 구문은 비동기 작업을 수행하고 그 결과를 처리할 수 있는 프로미스를 생성하는데 여기서 resolve와 reject는 프로미스의 상태를 변경하는 데 사용되는 콜백 함수입니다.
resolve: 프로미스를 성공 상태로 변경하고, 비동기 작업의 결과 값을 전달합니다.
reject: 프로미스를 실패 상태로 변경하고, 오류 정보를 전달합니다.
2. Async/Await 사용
- Async 함수와 Await 키워드를 사용하면 비동기 코드를 동기적으로 작성할 수 있어 이를 통해 콜백 지옥을 피할 수 있습니다. 아래의 예시를 통해 살펴볼게요.
1
2
3
4
5
6
7
8
9
10
11
12
async function processOrders(userId) {
try {
const user = await getUser(userId);
const orders = await getOrders(user);
const orderDetails = await getOrderDetails(orders[0]);
// 원하는 작업 수행
} catch (error) {
// 오류 처리
}
}
processOrders(userId);
2-1. Async함수
- async 함수는 함수 앞에 async 키워드를 붙여서 정의합니다. 이렇게 정의된 함수는 항상 프로미스를 반환하게 됩니다.
- async 함수 내부에서 await 키워드를 사용하여 비동기 작업의 완료를 기다릴 수 있습니다. 이때 await는 프로미스가 처리될 때까지 함수의 실행을 일시 중지시키고, 해당 프로미스가 처리되면 그 결과를 반환합니다.
- async 함수를 사용하면 비동기 코드를 동기식으로 작성할 수 있어 가독성이 높아지고, 콜백 지옥을 피할 수 있습니다.
2-2. Await키워드
- await 키워드는 async 함수 내에서만 사용할 수 있습니다. 비동기 작업의 완료를 기다리고 그 결과를 반환하는 역할을 합니다.
- await 키워드를 사용할 때에는 프로미스 앞에 붙여서 사용하며, 프로미스가 처리될 때까지 함수의 실행을 일시 중지시킵니다.
- await 키워드를 사용할 때 주의할 점은, await 키워드는 반드시 async 함수 내에서만 사용할 수 있으며, 최상위 레벨에서는 사용할 수 없습니다.
이렇게 오늘은 콜백 지옥에 대해 알아봤는데요,
콜백 지옥은 코드의 가독성과 유지보수성을 떨어뜨리므로, 프로미스나 Async/Await를 사용하여 비동기 코드를 더 간결하고 구조적으로 작성하는 것이 좋다는 거 잊지마세요!
오늘 정리한 내용도 면접을 준비할 때 나올 수 있는 질문인만큼 미리미리 숙지해서 알아두면 좋겠죠?
그럼 다음엔 또 다른 면접 정보들을 가져와보도록 하겠습니다 😁!