How to Call an Async Function in a Non-Async Function

A practical guide on how to handle asynchronous operations, like fetching data, when you're working inside a regular, non-async function in TypeScript.

Sometimes you have an async function, maybe one that fetches data or does some other operation that takes a bit of time, and you need to call it from a regular, non-async function. You can’t just await it directly, because await only works inside async functions.

Here’s how you can do it using .then() and .catch() with Promises. This lets you handle the result when the async function finishes, and also catch any errors that might pop up.

TypeScript
async function fetchData(): Promise<string> {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve("Data fetched successfully!");
        }, 1000);
    });
}

function processData() {
    console.log("Starting data processing...");

    // Call the async function and handle its Promise.
    fetchData()
        .then((data) => {
            // This code runs when fetchData() successfully resolves.
            console.log("Inside .then():", data);
            // You can do more stuff with the data here.
        })
        .catch((error) => {
            // This code runs if fetchData() rejects with an error.
            console.error("Inside .catch():", error);
        })
        .finally(() => {
            // This code runs no matter what, after the Promise settles (either resolves or rejects).
            console.log("Data processing finished.");
        });

    console.log(
        "processData() continues to run while fetchData() is in progress."
    );
}

// Let's run our non-async function.
processData();

// Expected output:
// Starting data processing...
// processData() continues to run while fetchData() is in progress.
// (after 1 second)
// Inside .then(): Data fetched successfully!
// Data processing finished.

In this example, processData is a normal function. When it calls fetchData(), fetchData() immediately returns a Promise. The .then() method is then used to say “when this Promise resolves, run this code with the data”. The .catch() method is for handling any errors. The processData function doesn’t wait for fetchData to finish; it keeps running its own code. The console.log("processData() continues to run...") line proves this by executing before the fetchData promise resolves.

Other recipes in Functions