Skip to content
On this page

Async Functions

In JavaScript, asynchronous operations require using Promises. A Promise object operates asynchronously when performing network operations, invoking a callback function upon completion: if successful, it calls then(), and if there’s an error, it calls catch(). While this asynchronous implementation prevents the user from feeling that the page is "stuck," writing multiple then() and catch() statements can be cumbersome and messy.

Is there a simpler way to write this?

You can use the async keyword in conjunction with await to call Promises, allowing asynchronous operations to resemble synchronous code:

javascript
async function get(url) {
    let resp = await fetch(url);
    let result = await resp.json();
    return result;
}

Using async function defines an asynchronous function, and asynchronous functions can be seen as equivalent to Promises. Inside an async function, you can use await to call another asynchronous function, which makes the syntax similar to synchronous code while executing asynchronously.

In other words:

javascript
let resp = await fetch(url);

Automatically implements asynchronous calling, which is equivalent to the following Promise code:

javascript
let promise = fetch(url);
promise.then((resp) => {
    // Handle resp
});

What if we want to implement catch()? The Promise approach would look like this:

javascript
let promise = fetch(url);
promise.then((resp) => {
    // Handle resp
}).catch(e => {
    // Handle error
});

When using await, you can simply employ traditional try { ... } catch syntax:

javascript
async function get(url) {
    try {
        let resp = await fetch(url);
        let result = await resp.json();
        return result;
    } catch (e) {
        // Handle error
    }
}

By defining asynchronous functions with async and calling them with await, the code resembles synchronous writing while greatly enhancing readability.

It’s crucial to note that await calls must occur within an async function and cannot be invoked in traditional synchronous code. So, how can a synchronous function call an async function?

Firstly, calling an asynchronous function directly with await in a regular function will result in an error:

javascript
async function get(url) {
    let resp = await fetch(url);
    return resp.json();
}

function doGet() {
    let data = await get('/api/categories'); // This will throw an error
}

doGet();

If you remove await, the function executes, but you won't receive the result directly, since you'll only get a Promise object:

javascript
async function get(url) {
    let resp = await fetch(url);
    let result = await resp.text();
    return result;
}

function doGet() {
    let promise = get('./content.html');
    console.log(promise); // Logs a Promise object
}

doGet();

Therefore, when calling an async function from a regular function, you cannot use await, but you can call the async function directly to obtain the Promise object and then chain then() and catch() to handle the results or errors:

javascript
async function get(url) {
    let resp = await fetch(url);
    let result = await resp.text();
    return result;
}

function doGet() {
    let promise = get('./content.html');
    promise.then(data => {
        // Handle data
        document.getElementById('test-response-text').value = JSON.stringify(data);
    });
}

doGet();

Response Results:

Thus, when defining asynchronous tasks, using async function is simpler than using Promises. When invoking asynchronous tasks, using await is more straightforward than using Promises, and capturing errors with the traditional try...catch syntax is also easier than using Promises. As long as the browser supports it, you can effectively implement asynchronous operations in a concise manner with async.

Async Functions has loaded