Lesson 24 of 50 – Async and Await

48% Completed
48%

Async and Await in Node.js

Async and await make asynchronous JavaScript easier to read and understand. They allow you to write Promise-based code in a style that looks similar to ordinary sequential code.

Important: An async function always returns a Promise. The await keyword is used inside an async function to wait for a Promise to settle before continuing that function.

1. What Is Async?

The async keyword is used before a function declaration to make the function asynchronous. An async function always returns a Promise.

Example: Async Function
async function greet() {
    return "Hello Student";
}

greet().then(function(message) {
    console.log(message);
});
Output:
Hello Student

greet() returns a Promise that fulfills with the value "Hello Student".

2. What Is Await?

The await keyword waits for a Promise to settle. If the Promise fulfills, await produces its result. If it rejects, await throws an error that can be handled using try...catch.

Example: Using Await
function getMessage() {
    return new Promise(function(resolve) {
        resolve("Welcome to Node.js");
    });
}

async function showMessage() {
    const message = await getMessage();
    console.log(message);
}

showMessage();
Output:
Welcome to Node.js

The await keyword waits for the Promise returned by getMessage() to fulfill before assigning its result to message.

3. Async and Await with setTimeout()

We can use a Promise with setTimeout() to demonstrate asynchronous operations that take some time.

Example: Waiting for Two Seconds
function waitTwoSeconds() {
    return new Promise(function(resolve) {
        setTimeout(function() {
            resolve("Two seconds completed!");
        }, 2000);
    });
}

async function start() {
    console.log("Please wait...");

    const result = await waitTwoSeconds();

    console.log(result);
}

start();
Output:
Please wait...
Two seconds completed!
The message appears after approximately two seconds. Await pauses the execution of the start() function at that point, but it does not block the entire Node.js event loop.

4. Async Function with Parameters

An async function can accept parameters and return calculated values. Its returned value is delivered through a Promise.

Example: Adding Two Numbers
async function add(a, b) {
    return a + b;
}

async function calculate() {
    const result = await add(10, 20);
    console.log("Sum:", result);
}

calculate();
Output:
Sum: 30

5. Error Handling with Try and Catch

Sometimes a Promise rejects because an operation fails. Use try...catch inside an async function to handle errors produced by an awaited Promise.

Example: Handling an Error
function checkNumber() {
    return new Promise(function(resolve, reject) {
        reject(new Error("Something went wrong!"));
    });
}

async function check() {
    try {
        const result = await checkNumber();
        console.log(result);
    } catch (error) {
        console.log("Error:", error.message);
    }
}

check();
Output:
Error: Something went wrong!

The rejected Promise throws an error at the await expression. The catch block handles that error.

6. Using Finally

The finally block runs after the try/catch process, whether the operation succeeds or fails.

Example: Try, Catch and Finally
async function processData() {
    try {
        console.log("Processing data...");
        throw new Error("Processing failed");
    } catch (error) {
        console.log(error.message);
    } finally {
        console.log("Process finished");
    }
}

processData();
Output:
Processing data...
Processing failed
Process finished

7. Sequential Await vs Promise.all()

When two asynchronous operations are independent, you can run them concurrently using Promise.all() instead of waiting for each one sequentially.

Example: Sequential Execution
function task(name, delay) {
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log(name);
            resolve();
        }, delay);
    });
}

async function runTasks() {
    await task("Task 1", 1000);
    await task("Task 2", 1000);
    console.log("All tasks completed");
}

runTasks();
Output:
Task 1
Task 2
All tasks completed

The second task starts only after the first task completes. The total waiting time is approximately two seconds.

Example: Concurrent Execution with Promise.all()
function task(name, delay) {
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log(name);
            resolve(name);
        }, delay);
    });
}

async function runTasks() {
    const results = await Promise.all([
        task("Task 1", 1000),
        task("Task 2", 1000)
    ]);

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

runTasks();
Example Output:
Task 1
Task 2
All tasks completed
[ 'Task 1', 'Task 2' ]
Both tasks start without waiting for the other. The total waiting time is approximately one second. Promise.all() preserves input order in its results array, even if the tasks finish in a different order.

8. Real-Life Example: Fetching Data

Async and await are commonly used to fetch data from APIs. The following example uses the built-in Node.js fetch() function available in modern Node.js versions.

Example: Fetch API Data
async function getUser() {
    try {
        const response = await fetch(
            "https://jsonplaceholder.typicode.com/users/1"
        );

        if (!response.ok) {
            throw new Error("HTTP error: " + response.status);
        }

        const user = await response.json();

        console.log("Name:", user.name);
        console.log("Email:", user.email);
    } catch (error) {
        console.log("Failed to fetch user:", error.message);
    }
}

getUser();

This example requires an internet connection. It sends an HTTP request, checks the response status, converts the response body to JSON, and handles possible errors.

A failed HTTP response does not automatically reject the fetch Promise. Check response.ok when you want to treat HTTP error statuses as errors.

9. Important Rules of Async and Await

Rule Explanation
async Makes a function return a Promise.
await Waits for a Promise to settle inside an async function.
try...catch Handles errors from awaited operations.
finally Runs after the try/catch process.
Promise.all() Waits for multiple Promises and returns their results.
Top-level await Supported in ES modules in modern Node.js. CommonJS files should use await inside an async function.

10. Practical Assignment

Practice these programs:
  1. Create an async function that returns your name.
  2. Use await to display the result of an async function.
  3. Create a Promise that resolves after three seconds.
  4. Use try/catch to handle a rejected Promise.
  5. Use finally to display "Program finished".
  6. Run two independent tasks using Promise.all().
  7. Fetch user data from an API and display the user's name.

Test Your Knowledge – Async and Await

Select the correct answer for each question.

1. What does an async function always return?
2. Which keyword is commonly used to handle errors from await?
3. Which method waits for multiple Promises and collects their results?