Node.js async, await Practice Questions with Solutions

Introduction

async/await provides a cleaner way to work with asynchronous operations in Node.js. It is built on top of Promises and makes asynchronous code easier to read and understand. In this chapter, you will practice creating async functions, using await, handling errors with try...catch, working with multiple asynchronous operations, using Promise.all(), reading files, and building practical Node.js examples from beginner to real-world level. Node.js async, await practice questions with solutions help to understand the concepts.

Question 1: How do you create a simple async function?

Problem

Create an async function that returns a simple message.

Solution

async function greet() {
    return "Hello from Node.js!";
}

greet().then((message) => {
    console.log(message);
});

Output

Hello from Node.js!

Step-by-Step Explanation

An async function is created by placing async before the function:

async function greet() {
    // Code
}

An async function always returns a Promise.

So:

return "Hello from Node.js!";

is automatically treated like a resolved Promise.

We can handle the returned Promise using:

greet().then((message) => {
    console.log(message);
});

Question 2: How do you use await with a Promise?

Problem

Create a Promise and use await to get its result inside an async function.

Solution

function getMessage() {

    return Promise.resolve("Data received successfully.");
}

async function showMessage() {

    const message = await getMessage();

    console.log(message);
}

showMessage();

Output

Data received successfully.

Step-by-Step Explanation

The function:

getMessage()

returns a Promise.

Inside the async function, we use:

const message = await getMessage();

await waits for the Promise to settle before assigning its fulfilled value to message.


Question 3: How do you use async/await with setTimeout()?

Problem

Create an asynchronous function that waits for two seconds before returning a message.

Solution

function waitTwoSeconds() {

    return new Promise((resolve) => {

        setTimeout(() => {

            resolve("Two seconds completed.");

        }, 2000);

    });
}

async function start() {

    console.log("Waiting...");

    const message = await waitTwoSeconds();

    console.log(message);
}

start();

Output

Immediately:

Waiting...

After approximately two seconds:

Two seconds completed.

Step-by-Step Explanation

setTimeout() does not directly return a Promise, so we wrap it inside one:

return new Promise((resolve) => {
    setTimeout(() => {
        resolve("Two seconds completed.");
    }, 2000);
});

Then:

const message = await waitTwoSeconds();

waits for the Promise to resolve.

Question 4: How do you handle errors using async/await?

Problem

Create an asynchronous function that handles a rejected Promise using try...catch.

Solution

function getUser() {

    return Promise.reject(
        new Error("User could not be found.")
    );
}

async function showUser() {

    try {

        const user = await getUser();

        console.log(user);

    } catch (error) {

        console.log("Error:", error.message);
    }
}

showUser();

Output

Error: User could not be found.

Step-by-Step Explanation

The Promise is rejected:

return Promise.reject(
    new Error("User could not be found.")
);

The await expression receives the rejected Promise.

Because the await operation fails, execution moves to the catch block:

catch (error) {
    console.log("Error:", error.message);
}

Question 5: How do you use async/await with the File System module?

Problem

Read a text file asynchronously using async/await.

Solution

Create a file named message.txt:

Welcome to Node.js!

Create index.js:

const fs = require("fs").promises;

async function readMessage() {

    try {

        const data = await fs.readFile(
            "message.txt",
            "utf8"
        );

        console.log(data);

    } catch (error) {

        console.log("Error:", error.message);
    }
}

readMessage();

Output

Welcome to Node.js!

Step-by-Step Explanation

We import the Promise-based File System API:

const fs = require("fs").promises;

Then read the file:

const data = await fs.readFile(
    "message.txt",
    "utf8"
);

The await waits for the file-reading Promise to complete.


Question 6: How do you perform multiple async/await operations in sequence?

Problem

Create three asynchronous tasks and execute them one after another.

Solution

function firstTask() {

    return new Promise((resolve) => {

        setTimeout(() => {

            resolve("First task completed.");

        }, 1000);

    });
}

function secondTask() {

    return new Promise((resolve) => {

        setTimeout(() => {

            resolve("Second task completed.");

        }, 1000);

    });
}

function thirdTask() {

    return new Promise((resolve) => {

        setTimeout(() => {

            resolve("Third task completed.");

        }, 1000);

    });
}

async function runTasks() {

    const first = await firstTask();

    console.log(first);

    const second = await secondTask();

    console.log(second);

    const third = await thirdTask();

    console.log(third);

    console.log("All tasks completed.");
}

runTasks();

Output

After approximately one second:

First task completed.

After approximately two seconds:

Second task completed.

After approximately three seconds:

Third task completed.
All tasks completed.

Step-by-Step Explanation

The first task starts:

const first = await firstTask();

Only after it completes does the second task start:

const second = await secondTask();

Then the third task starts:

const third = await thirdTask();

Execution Flow

firstTask()
    ↓
secondTask()
    ↓
thirdTask()

Question 7: How do you run multiple async operations at the same time?

Problem

Run three independent asynchronous operations concurrently using Promise.all() with async/await.

Solution

function getUser() {

    return new Promise((resolve) => {

        setTimeout(() => {

            resolve("User data");

        }, 2000);

    });
}

function getCourses() {

    return new Promise((resolve) => {

        setTimeout(() => {

            resolve("Course data");

        }, 2000);

    });
}

function getMessages() {

    return new Promise((resolve) => {

        setTimeout(() => {

            resolve("Message data");

        }, 2000);

    });
}

async function loadData() {

    try {

        const [user, courses, messages] = await Promise.all([
            getUser(),
            getCourses(),
            getMessages()
        ]);

        console.log(user);
        console.log(courses);
        console.log(messages);

    } catch (error) {

        console.log("Error:", error.message);
    }
}

loadData();

Output

After approximately two seconds:

User data
Course data
Message data

Step-by-Step Explanation

If you write:

const user = await getUser();
const courses = await getCourses();
const messages = await getMessages();

the operations are performed sequentially.

Instead, we start all three Promises together:

Promise.all([
    getUser(),
    getCourses(),
    getMessages()
])

Then wait for all of them:

const [user, courses, messages] = await Promise.all([...]);

Question 8: How do you use async/await with function parameters?

Problem

Create an asynchronous function that accepts a student ID and returns student information.

Solution

const students = [
    {
        id: 1,
        name: "Rahul",
        course: "Node.js"
    },
    {
        id: 2,
        name: "Priya",
        course: "JavaScript"
    }
];

function findStudent(id) {

    return new Promise((resolve, reject) => {

        const student = students.find(
            (student) => student.id === id
        );

        if (!student) {

            reject(
                new Error("Student not found.")
            );

            return;
        }

        resolve(student);
    });
}

async function showStudent(id) {

    try {

        const student = await findStudent(id);

        console.log("Student:", student);

    } catch (error) {

        console.log("Error:", error.message);
    }
}

showStudent(1);

Output

Student: { id: 1, name: 'Rahul', course: 'Node.js' }

The exact console formatting can vary slightly by Node.js version.

Step-by-Step Explanation

The function receives an ID:

findStudent(id)

It searches the array:

const student = students.find(
    (student) => student.id === id
);

If the student does not exist:

reject(new Error("Student not found."));

If the student exists:

resolve(student);

The async function waits for the result:

const student = await findStudent(id);

Question 9: How do you use async/await with JSON data?

Problem

Read a JSON file, convert its content into a JavaScript array, and display the students.

Solution

Create students.json:

[
    {
        "id": 1,
        "name": "Rahul",
        "course": "Node.js"
    },
    {
        "id": 2,
        "name": "Priya",
        "course": "Python"
    },
    {
        "id": 3,
        "name": "Aman",
        "course": "JavaScript"
    }
]

Create index.js:

const fs = require("fs").promises;

async function getStudents() {

    try {

        const data = await fs.readFile(
            "students.json",
            "utf8"
        );

        const students = JSON.parse(data);

        return students;

    } catch (error) {

        throw new Error(
            "Unable to load student data."
        );
    }
}

async function showStudents() {

    try {

        const students = await getStudents();

        students.forEach((student) => {

            console.log(
                `${student.id}. ${student.name} - ${student.course}`
            );

        });

    } catch (error) {

        console.log("Error:", error.message);
    }
}

showStudents();

Output

1. Rahul - Node.js
2. Priya - Python
3. Aman - JavaScript

Step-by-Step Explanation

First, read the file:

const data = await fs.readFile(
    "students.json",
    "utf8"
);

The file content is a string.

For example:

"[{\"id\":1,\"name\":\"Rahul\"...}]"

We convert it into JavaScript data:

const students = JSON.parse(data);

Then return the array:

return students;

The showStudents() function waits for it:

const students = await getStudents();

Finally, forEach() displays each student.


Question 10: How do you build a practical async/await Node.js application?

Problem

Build a small student API using Express and async/await.

The API should:

  • Return all students.
  • Return one student by ID.
  • Handle invalid IDs.
  • Handle missing students.
  • Use asynchronous functions.
  • Handle errors using try...catch.

Solution

Install Express:

npm install express

Create index.js:

const express = require("express");

const app = express();

app.use(express.json());

const students = [
    {
        id: 1,
        name: "Rahul",
        course: "Node.js"
    },
    {
        id: 2,
        name: "Priya",
        course: "JavaScript"
    },
    {
        id: 3,
        name: "Aman",
        course: "Python"
    }
];

function getStudents() {

    return new Promise((resolve) => {

        setTimeout(() => {

            resolve(students);

        }, 500);

    });
}

function getStudentById(id) {

    return new Promise((resolve, reject) => {

        setTimeout(() => {

            const student = students.find(
                (student) => student.id === id
            );

            if (!student) {

                reject(
                    new Error("Student not found.")
                );

                return;
            }

            resolve(student);

        }, 500);
    });
}

app.get("/students", async (req, res) => {

    try {

        const students = await getStudents();

        res.json({
            success: true,
            data: students
        });

    } catch (error) {

        res.status(500).json({
            success: false,
            error: error.message
        });
    }
});

app.get("/students/:id", async (req, res) => {

    try {

        const id = Number(req.params.id);

        if (Number.isNaN(id)) {

            return res.status(400).json({
                success: false,
                error: "Student ID must be a number."
            });
        }

        const student = await getStudentById(id);

        res.json({
            success: true,
            data: student
        });

    } catch (error) {

        res.status(404).json({
            success: false,
            error: error.message
        });
    }
});

app.listen(3000, () => {

    console.log(
        "Server running on http://localhost:3000"
    );
});

Output

Server running on http://localhost:3000

Test 1: Get All Students

Open:

http://localhost:3000/students

Output:

{
    "success": true,
    "data": [
        {
            "id": 1,
            "name": "Rahul",
            "course": "Node.js"
        },
        {
            "id": 2,
            "name": "Priya",
            "course": "JavaScript"
        },
        {
            "id": 3,
            "name": "Aman",
            "course": "Python"
        }
    ]
}

Test 2: Get One Student

Open:

http://localhost:3000/students/1

Output:

{
    "success": true,
    "data": {
        "id": 1,
        "name": "Rahul",
        "course": "Node.js"
    }
}

Test 3: Student Does Not Exist

Open:

http://localhost:3000/students/10

Output:

{
    "success": false,
    "error": "Student not found."
}

HTTP status:

404

Test 4: Invalid Student ID

Open:

http://localhost:3000/students/abc

Output:

{
    "success": false,
    "error": "Student ID must be a number."
}

HTTP status:

400

Step-by-Step Explanation

Step 1: Create asynchronous functions

function getStudents() {
    return new Promise(...);
}

and:

function getStudentById(id) {
    return new Promise(...);
}

These functions simulate asynchronous operations.

Step 2: Use async route handlers

app.get("/students", async (req, res) => {

The async keyword allows us to use await.

Step 3: Wait for the data

const students = await getStudents();

The route waits for the Promise to resolve before sending the response.

Step 4: Handle errors

try {
    // Asynchronous operation
} catch (error) {
    // Error response
}

Step 5: Validate user input

const id = Number(req.params.id);

Then:

if (Number.isNaN(id)) {
    // Invalid ID
}

Step 6: Return the result

res.json({
    success: true,
    data: student
});

Complete Flow

Client Request
      ↓
Express Route
      ↓
async function
      ↓
await Promise
      ↓
Data available?
   ↙          ↘
 Yes           No
  ↓             ↓
res.json()   catch()
                ↓
           Error Response

Key Takeaways

  • async/await provides a cleaner way to work with Promises.
  • An async function always returns a Promise.
  • await waits for a Promise to settle and gives the fulfilled value when successful.
  • await is normally used inside an async function.
  • try...catch is commonly used to handle errors with async/await.
  • async/await does not make asynchronous operations synchronous.
  • await pauses the current async function while the Promise is pending.
  • Node.js can continue handling other work while an asynchronous operation is waiting.
  • Multiple await statements executed one after another run their operations sequentially.
  • Promise.all() can be used with await when independent operations should run concurrently.
  • fs.promises provides Promise-based File System methods that work naturally with async/await.
  • JSON data can be read asynchronously and converted using JSON.parse().
  • Errors from rejected Promises can be caught using try...catch.
  • Functions using async/await can accept parameters just like normal functions.
  • Express route handlers can use async functions.
  • Input validation should be performed before using values from URLs or requests.
  • async/await is built on top of Promises; understanding Promises makes async/await easier to learn.
  • async/await can make asynchronous Node.js applications easier to read and maintain.

FAQs

1. What is async/await in Node.js?

async/await is a syntax used to work with Promises in a more readable way.

Example:

async function getData() {

    const data = await fetchData();

    console.log(data);
}

The async keyword creates an asynchronous function, while await waits for a Promise result.

2. Does an async function always return a Promise?

Yes.

For example:

async function greet() {
    return "Hello";
}

Even though "Hello" is returned directly, the function actually returns a Promise.

You can handle it with:

greet().then((message) => {
    console.log(message);
});

3. Can I use await without async?

In most regular Node.js code, await is used inside an async function.

For example:

async function getUser() {

    const user = await fetchUser();

    console.log(user);
}

Modern JavaScript also supports top-level await in appropriate ES module contexts, but beginners will commonly encounter await inside async functions.

4. How do I handle errors with async/await?

Use try...catch:

async function getData() {

    try {

        const data = await fetchData();

        console.log(data);

    } catch (error) {

        console.log("Error:", error.message);
    }
}

If the Promise awaited inside the try block rejects, control moves to catch.

5. What is the difference between await and then()?

Both can be used to work with Promises.

Using .then():

getUser()
    .then((user) => {
        console.log(user);
    });

Using async/await:

async function showUser() {

    const user = await getUser();

    console.log(user);
}

async/await often makes sequential asynchronous code easier to read.

6. Does await block the Node.js server?

No. await does not block the entire Node.js event loop while a Promise is pending.

It pauses the execution of the current async function until the awaited Promise settles, allowing Node.js to continue handling other work.

7. How can I run multiple Promises at the same time with async/await?

Use Promise.all():

async function loadData() {

    const [users, courses] = await Promise.all([
        getUsers(),
        getCourses()
    ]);

    console.log(users);
    console.log(courses);
}

This is useful when the operations are independent and do not need to wait for each other.

Written by Shubhranshu Shekhar, who has trained 20000+ students in coding.

Scroll to Top