Functionsbeginner
Callbacks and Callback Hell
Passing a function to be executed later, and why deeply nested callbacks became a maintainability problem promises and async/await later solved.
A callback is a function passed to another function to be called later. It is the oldest way JavaScript handles anything asynchronous.
A callback is like leaving your phone number with a restaurant host and going to wait at the bar — instead of standing in line asking 'is my table ready?' over and over (blocking), you get called back the moment it's ready, and can drink at the bar in the meantime (non-blocking).
Key Concepts
1
fs.readFile('a.txt', (err, data) => {
if (err) return handle(err);
console.log(data);
});2
The Node convention: error first. The callback's first parameter is the error, and it is null on
success. That convention exists because there is no try/catch that can reach across the asynchronous
boundary.
nulltry/catch
3
Callback hell is what happens when they nest.
getUser(id, (err, user) => {
if (err) return handle(err);
getOrders(user.id, (err, orders) => {
if (err) return handle(err);
getDetails(orders[0].id, (err, details) => {
if (err) return handle(err);
render(details);
});
});
});4
Three separate problems, which is why it is worse than ugly.Error handling repeats at every level, and missing one loses the error silently.
5
The shape drifts right, so the logic is hard to follow and hard to change.
6
Sequencing is manual. Running two of these in parallel and waiting for both means writing a counter by
hand.
7
Promises fixed the nesting.
getUser(id)
.then(user => getOrders(user.id))
.then(orders => getDetails(orders[0].id))
.then(render)
.catch(handle); // one handler for all of it8
async/await made it read like the synchronous version.
try {
const user = await getUser(id);
const orders = await getOrders(user.id);
render(await getDetails(orders[0].id));
} catch (err) {
handle(err);
}async/await
9
Same behaviour, and now try/catch works, and control flow — loops, conditionals, early returns — behaves
normally.
try/catch
10
Callbacks have not gone away. Event handlers, array methods, setTimeout and observers are all
callbacks, and they are the right shape for something that happens many times.
setTimeout
11
The distinction: a callback suits repeated events; a promise suits a single eventual result. Callback hell
was what happened when promises did not exist and the second case had to use the first.
12
What the interviewer is probing.1. "What problem do promises solve that callbacks have?" Probing: beyond nesting. Stalls:
"They look nicer." Moves up: errors propagate through a chain rather than needing handling at each
level, and the callback is guaranteed to fire once.
13
2. "What is the error-first convention?" Probing: the Node pattern. Stalls: "An old style."
Moves up: the first parameter is the error and the second the result, so every caller checks it
explicitly.
14
3. "How do you flatten nested callbacks without promises?" Probing: structure. Stalls: "You
cannot." Moves up: name the functions and pass references rather than nesting anonymous ones,
which flattens the shape.
15
4. "What is a common double-callback bug?" Probing: the guarantee callbacks lack. Stalls:
"Not possible." Moves up: calling back in an error branch without returning, so the success path
runs too — promises cannot settle twice.