Introduction
Callbacks are one of the fundamental concepts in Node.js. A callback is a function passed to another function so it can be executed later, often after an asynchronous operation finishes. In this chapter, you will practice simple callbacks, callback parameters, asynchronous callbacks, file operations, error-first callbacks, nested callbacks, and practical Node.js examples. The examples gradually move from beginner level to real-world callback handling. Node.js Callbacks Practice Questions with Solutions help to understand the concepts.
Question 1: How do you create a simple callback function?
Problem
Create a function that accepts another function as a callback and executes it after displaying a message.
Solution
function greet(name, callback) {
console.log("Hello " + name);
callback();
}
function showMessage() {
console.log("Welcome to Node.js!");
}
greet("Rahul", showMessage);
Output
Hello Rahul
Welcome to Node.js!
Step-by-Step Explanation
The greet() function accepts two parameters:
function greet(name, callback)
The second parameter is a callback function.
Inside greet():
callback();
executes the callback.
We then pass showMessage as the callback:
greet("Rahul", showMessage);
Question 2: How do you pass data to a callback?
Problem
Create a function that calculates the square of a number and sends the result to a callback.
Solution
function calculateSquare(number, callback) {
const result = number * number;
callback(result);
}
function displayResult(result) {
console.log("Square:", result);
}
calculateSquare(6, displayResult);
Output
Square: 36
Step-by-Step Explanation
The calculateSquare() function receives:
number
callback
It calculates:
const result = number * number;
Then sends the result to the callback:
callback(result);
The callback receives the value:
function displayResult(result)
Important Point
Callbacks can receive data through function arguments.
Question 3: How do callbacks work with asynchronous code?
Problem
Create an asynchronous function that displays a message after two seconds and then executes a callback.
Solution
function downloadFile(callback) {
console.log("Downloading file...");
setTimeout(() => {
console.log("File downloaded.");
callback();
}, 2000);
}
function downloadComplete() {
console.log("Download completed successfully!");
}
downloadFile(downloadComplete);
Output
Immediately:
Downloading file...
After approximately 2 seconds:
File downloaded.
Download completed successfully!
Step-by-Step Explanation
setTimeout() schedules code to run later:
setTimeout(() => {
// Code
}, 2000);
After the timeout finishes, the callback is executed:
callback();
This is an example of an asynchronous callback.
Question 4: How do you use a callback to perform addition?
Problem
Create a function that accepts two numbers and uses a callback to return their sum.
Solution
function addNumbers(a, b, callback) {
const sum = a + b;
callback(sum);
}
function showSum(result) {
console.log("Sum:", result);
}
addNumbers(20, 30, showSum);
Output
Sum: 50
Step-by-Step Explanation
The function receives:
a
b
callback
It calculates:
const sum = a + b;
Then passes the result to the callback:
callback(sum);
The callback receives 50 and displays it.
Try It Yourself
Change:
addNumbers(20, 30, showSum);
to:
addNumbers(100, 250, showSum);
Output:
Sum: 350
Question 5: How do you use the error-first callback pattern?
Problem
Create a function that checks a number and returns either an error or a successful result through a callback.
Solution
function checkNumber(number, callback) {
if (number < 0) {
callback(
new Error("Number cannot be negative."),
null
);
return;
}
callback(null, number);
}
checkNumber(10, (error, result) => {
if (error) {
console.log("Error:", error.message);
return;
}
console.log("Number:", result);
});
Output
Number: 10
Step-by-Step Explanation
Node.js commonly uses an error-first callback pattern.
The callback receives:
(error, result)
When an error occurs:
callback(error, null);
When the operation succeeds:
callback(null, result);
The caller checks the error first:
if (error) {
// Handle error
}
Question 6: How do you use callbacks with the Node.js File System module?
Problem
Create a file and then read it using asynchronous callbacks.
Solution
const fs = require("fs");
fs.writeFile(
"message.txt",
"Hello from Node.js!",
(error) => {
if (error) {
console.log("Error writing file:", error.message);
return;
}
console.log("File created successfully.");
fs.readFile(
"message.txt",
"utf8",
(error, data) => {
if (error) {
console.log(
"Error reading file:",
error.message
);
return;
}
console.log("File content:", data);
}
);
}
);
Output
File created successfully.
File content: Hello from Node.js!
Step-by-Step Explanation
First, writeFile() creates the file:
fs.writeFile(...)
Its callback runs after the operation finishes.
After the file is successfully created, readFile() is called:
fs.readFile(...)
Its callback receives:
(error, data)
The data contains the file content.
Question 7: How do you execute multiple callbacks in sequence?
Problem
Create three functions that run one after another using callbacks.
Solution
function firstTask(callback) {
console.log("First task completed.");
callback();
}
function secondTask(callback) {
console.log("Second task completed.");
callback();
}
function thirdTask() {
console.log("Third task completed.");
}
firstTask(() => {
secondTask(() => {
thirdTask();
});
});
Output
First task completed.
Second task completed.
Third task completed.
Step-by-Step Explanation
The first function receives a callback:
firstTask(() => {
...
});
After completing its work, it calls the callback.
The callback starts the second task:
secondTask(() => {
...
});
After the second task finishes, the third task starts.
Question 8: What is callback hell?
Problem
Understand a situation where multiple nested callbacks make code difficult to read.
Solution
Consider:
function login(username, callback) {
console.log("User logged in.");
callback();
}
function getProfile(callback) {
console.log("Profile loaded.");
callback();
}
function getCourses(callback) {
console.log("Courses loaded.");
callback();
}
function showDashboard() {
console.log("Dashboard displayed.");
}
login("Rahul", () => {
getProfile(() => {
getCourses(() => {
showDashboard();
});
});
});
Output
User logged in.
Profile loaded.
Courses loaded.
Dashboard displayed.
Step-by-Step Explanation
The callbacks are nested:
login()
└── getProfile()
└── getCourses()
└── showDashboard()
With many asynchronous operations, this pattern can become deeply nested and difficult to maintain.
This situation is commonly called callback hell or the pyramid of doom.
Question 9: How do you create a reusable callback-based function?
Problem
Create a reusable function that performs an operation and allows different callbacks to handle the result.
Solution
function calculate(a, b, operation, callback) {
let result;
if (operation === "add") {
result = a + b;
} else if (operation === "subtract") {
result = a - b;
} else {
callback(
new Error("Unknown operation."),
null
);
return;
}
callback(null, result);
}
calculate(20, 10, "add", (error, result) => {
if (error) {
console.log("Error:", error.message);
return;
}
console.log("Result:", result);
});
Output
Result: 30
Step-by-Step Explanation
The function accepts four parameters:
calculate(
a,
b,
operation,
callback
)
It checks the requested operation.
For addition:
result = a + b;
For subtraction:
result = a - b;
Then the callback receives:
callback(null, result);
Question 10: How do you build a practical callback-based Node.js application?
Problem
Create a small Node.js program that:
- Reads student data from a file.
- Parses JSON.
- Handles file errors.
- Handles invalid JSON.
- Sends the final student data to a callback.
Solution
First create students.json:
[
{
"id": 1,
"name": "Rahul",
"course": "Node.js"
},
{
"id": 2,
"name": "Priya",
"course": "JavaScript"
}
]
Now create index.js:
const fs = require("fs");
function getStudents(callback) {
fs.readFile(
"students.json",
"utf8",
(error, data) => {
if (error) {
callback(
new Error("Unable to read students file."),
null
);
return;
}
let students;
try {
students = JSON.parse(data);
} catch (error) {
callback(
new Error("Invalid student JSON data."),
null
);
return;
}
callback(null, students);
}
);
}
getStudents((error, students) => {
if (error) {
console.log("Error:", error.message);
return;
}
console.log("Students:");
students.forEach((student) => {
console.log(
`${student.id}. ${student.name} - ${student.course}`
);
});
});
Output
Students:
1. Rahul - Node.js
2. Priya - JavaScript
Step-by-Step Explanation
Step 1: Import File System
const fs = require("fs");
The fs module provides file system functionality.
Step 2: Create a reusable function
function getStudents(callback)
The function accepts a callback to return the final result.
Step 3: Read the JSON file
fs.readFile(
"students.json",
"utf8",
(error, data) => {
The operation is asynchronous.
Step 4: Check for file errors
if (error) {
callback(
new Error("Unable to read students file."),
null
);
return;
}
If the file cannot be read, the callback receives an error.
Step 5: Parse JSON
students = JSON.parse(data);
Because JSON parsing can throw an exception, it is placed inside try...catch.
Step 6: Return the data
callback(null, students);
The first argument is null because there is no error.
Step 7: Handle the result
getStudents((error, students) => {
The caller checks the error:
if (error) {
console.log(error.message);
return;
}
If everything succeeds, the student data is displayed.
Key Takeaways
- A callback is a function passed to another function.
- The receiving function can execute the callback when its work is complete.
- Callbacks can receive data through parameters.
- Node.js uses callbacks extensively for asynchronous operations.
setTimeout()is a simple way to understand asynchronous callbacks.- Node.js traditionally uses the error-first callback pattern.
- The error-first pattern commonly looks like:
callback(error, result);
- Successful operations commonly use:
callback(null, result);
- Errors should be checked before processing callback results.
- The Node.js
fsmodule provides many callback-based asynchronous methods. - Callbacks can be used to control the order of asynchronous operations.
- Too many nested callbacks can create callback hell.
- Promises and
async/awaitprovide alternative ways to manage complex asynchronous operations. - Callbacks are still important because many Node.js APIs and libraries use them.
- A good callback-based function should clearly define what arguments its callback receives.
- Error handling should be included in asynchronous callback code.
- Reusable callback functions can make Node.js code more flexible.
- Understanding callbacks makes it easier to understand Promises and
async/await.
FAQs
1. What is a callback in Node.js?
A callback is a function passed as an argument to another function so that it can be executed later.
Example:
function greet(name, callback) {
console.log("Hello " + name);
callback();
}
Here, callback is a function parameter.
2. Why are callbacks important in Node.js?
Callbacks are important because Node.js performs many operations asynchronously.
For example, file reading can continue without blocking the rest of the application:
fs.readFile("file.txt", "utf8", (error, data) => {
// Handle result
});
The callback runs after the file operation finishes.
3. What is an error-first callback?
An error-first callback is a common Node.js convention where the first callback argument represents an error.
Example:
callback(error, data);
When the operation succeeds:
callback(null, data);
The caller normally checks the error first.
4. What is callback hell in Node.js?
Callback hell occurs when many callbacks become deeply nested, making code difficult to read and maintain.
Example:
first()
└── second()
└── third()
└── fourth()
Promises and async/await can make complex asynchronous flows easier to manage.
5. Are callbacks asynchronous in Node.js?
Not always.
A callback is simply a function passed to another function. Whether it runs synchronously or asynchronously depends on the function that receives it.
For example, this callback runs synchronously:
function test(callback) {
callback();
}
test(() => {
console.log("Hello");
});
But a callback passed to an asynchronous API such as fs.readFile() runs after the asynchronous operation completes.
6. How do you handle errors in a callback?
Use the error-first pattern and check the error before using the result.
Example:
someFunction((error, result) => {
if (error) {
console.log(error.message);
return;
}
console.log(result);
});
This prevents the application from processing an invalid or missing result.
7. What is the difference between callbacks and Promises?
Callbacks pass a function to another function to handle the result.
Promises represent the eventual completion or failure of an asynchronous operation and can be handled using .then() and .catch().
Callback example:
getData((error, data) => {
// Handle result
});
Promise example:
getData()
.then((data) => {
// Handle result
})
.catch((error) => {
// Handle error
});
Both approaches are important to understand when learning asynchronous Node.js programming.
Written by Shubhranshu Shekhar, who has trained 20000+ students in coding.
