What is callback hell and how can you avoid it? Callback hell क्या है और इससे कैसे बचें?
Callback hell (also called pyramid of doom) occurs when multiple nested callbacks are used, making the code hard to read and maintain. This is especially common in asynchronous operations.
// CALLBACK HELL - Hard to read
function getUserData(userId, callback) {
getUser(userId, function(err, user) {
if (err) {
callback(err);
} else {
getOrders(user.id, function(err, orders) {
if (err) {
callback(err);
} else {
getOrderDetails(orders[0].id, function(err, details) {
if (err) {
callback(err);
} else {
getPaymentInfo(details.id, function(err, payment) {
if (err) {
callback(err);
} else {
callback(null, {
user: user,
orders: orders,
details: details,
payment: payment
});
}
});
}
});
}
});
}
});
}
getUserData(123, function(err, result) {
if (err) {
console.log('Error:', err);
} else {
console.log('User Data:', result);
}
});
// SOLUTION 1: Named callback functions (modularity)
function handleUser(err, user) {
if (err) return handleError(err);
getOrders(user.id, handleOrders.bind(null, user));
}
function handleOrders(user, err, orders) {
if (err) return handleError(err);
getOrderDetails(orders[0].id, handleDetails.bind(null, user, orders));
}
function handleDetails(user, orders, err, details) {
if (err) return handleError(err);
getPaymentInfo(details.id, handlePayment.bind(null, user, orders, details));
}
function handlePayment(user, orders, details, err, payment) {
if (err) return handleError(err);
console.log({ user, orders, details, payment });
}
function handleError(err) {
console.log('Error:', err);
}
getUser(123, handleUser);
// SOLUTION 2: Promises - Much cleaner
function getUserDataPromise(userId) {
return getUser(userId)
.then(user => getOrders(user.id).then(orders => ({ user, orders })))
.then(data => getOrderDetails(data.orders[0].id)
.then(details => ({ ...data, details })))
.then(data => getPaymentInfo(data.details.id)
.then(payment => ({ ...data, payment })))
.catch(error => console.log('Error:', error));
}
getUserDataPromise(123).then(result => {
console.log('User Data:', result);
});
// SOLUTION 3: Promises with better readability
function getUserDataPromise2(userId) {
let userData = {};
return getUser(userId)
.then(user => {
userData.user = user;
return getOrders(user.id);
})
.then(orders => {
userData.orders = orders;
return getOrderDetails(orders[0].id);
})
.then(details => {
userData.details = details;
return getPaymentInfo(details.id);
})
.then(payment => {
userData.payment = payment;
return userData;
})
.catch(error => console.log('Error:', error));
}
// SOLUTION 4: async/await - Most readable (BEST)
async function getUserDataAsync(userId) {
try {
const user = await getUser(userId);
const orders = await getOrders(user.id);
const details = await getOrderDetails(orders[0].id);
const payment = await getPaymentInfo(details.id);
return { user, orders, details, payment };
} catch (error) {
console.log('Error:', error);
}
}
// Usage
getUserDataAsync(123).then(result => {
console.log('User Data:', result);
});
// Or with await
async function main() {
const result = await getUserDataAsync(123);
console.log('User Data:', result);
}
main();Interview tip: Show the progression from callback hell to modern solutions. Explain that while the code in callback hell works, it's hard to understand and maintain. Demonstrate how Promises flatten the nesting, and async/await makes it look like synchronous code. Mention that async/await is now the modern standard.
Callback hell (pyramid of doom कहा जाता है) तब होता है जब multiple nested callbacks का use होता है, जिससे code समझना और maintain करना मुश्किल हो जाता है। Asynchronous operations में यह बहुत आम है।
// CALLBACK HELL - पढ़ना मुश्किल
getUser(userId, function(err, user) {
if (err) callback(err);
else {
getOrders(user.id, function(err, orders) {
if (err) callback(err);
else {
getOrderDetails(orders[0].id, function(err, details) {
if (err) callback(err);
else {
getPaymentInfo(details.id, function(err, payment) {
if (err) callback(err);
else callback(null, { user, orders, details, payment });
});
}
});
}
});
}
});
// SOLUTION 1: Named functions
function handleUser(err, user) {
if (err) return handleError(err);
getOrders(user.id, handleOrders.bind(null, user));
}
function handleOrders(user, err, orders) {
if (err) return handleError(err);
getOrderDetails(orders[0].id, handleDetails);
}
// SOLUTION 2: Promises
getUser(userId)
.then(user => getOrders(user.id))
.then(orders => getOrderDetails(orders[0].id))
.then(details => getPaymentInfo(details.id))
.then(payment => console.log(payment))
.catch(error => console.log('Error:', error));
// SOLUTION 3: async/await (BEST)
async function getUserData(userId) {
try {
const user = await getUser(userId);
const orders = await getOrders(user.id);
const details = await getOrderDetails(orders[0].id);
const payment = await getPaymentInfo(details.id);
return { user, orders, details, payment };
} catch (error) {
console.log('Error:', error);
}
}इंटरव्यू टिप: Progression show करें callback hell से modern solutions तक। समझाएं code काम तो करता है पर समझना-maintain करना मुश्किल है। Promises कैसे nesting को flatten करते हैं, और async/await कैसे synchronous code की तरह दिखता है।
Was this answer clear?