Skip to main content

Async and Await Keywords in JavaScript – Definition, Meaning, & Examples

The async and await keywords simplify creating and managing promises in JavaScript.

What Is the async Keyword in JavaScript?

The async keyword turns a regular function into an asynchronous function that returns a promise object rather than a regular JavaScript data type.

Here's an example:

async function myMomsPromise() {}

console.log(myMomsPromise());

// The invocation above will return:
Promise { <state>: "fulfilled", <value>: undefined }

Placing the async keyword before myMomsPromise() turns the function into an asynchronous function. Therefore, the invocation returned a promise object.

By default, an asynchronous function returns a promise object that JavaScript resolves with the function's returned value or rejects based on the exception thrown.

In other words, the async keyword will automatically pass an asynchronous function's return value through the Promise.resolve() static method.

Regular Function vs. Asynchronous Function in JavaScript

A regular function returns a regular value. For instance, the regular function below returns a regular string value.

function myMomsPromise() {
return "I get a book";
}

// Invoke the myMomsPromise() regular function:
console.log(myMomsPromise());

// The invocation above will return: "I get a book"

But an async function returns a promise object. For instance, below is an asynchronous function that returns a fulfilled promise.

async function myMomsPromise() {
return 'I get a book';
}

// Invoke the myMomsPromise() asynchronous function:
console.log(myMomsPromise());

// The invocation above will return:
Promise { <state>: "fulfilled", <value>: "I get a book" }

The async keyword in the snippet above instructed the function to return a promise object rather than directly outputting the string value.

Here is the function expression equivalence of the above asynchronous function:

// Create an async function expression:
const myMomsPromise = async function () {
return "I get a book";
};

// Check myMomsPromise's content:
console.log(myMomsPromise());

// The invocation above will return:
Promise { <state>: "fulfilled", <value>: "I get a book" }

You can also write the asynchronous function as an arrow function like so:

// Create an async arrow function expression:
const myMomsPromise = async () => "I get a book";

// Check myMomsPromise's content:
console.log(myMomsPromise());

// The invocation above will return:
Promise { <state>: "fulfilled", <value>: "I get a book" }

Important Stuff to Know about Creating Promise Objects

Here are three essential facts to remember when creating promises in JavaScript.

Regular functions can create promises

A regular function can use the Promise constructor's static methods to create promises. For instance, the regular function below uses the Promise.resolve() method to return a promise object.

function myMomsPromise() {
return Promise.resolve('I get a book');
}

// Invoke the myMomsPromise() asynchronous function:
console.log(myMomsPromise());

// The invocation above will return:
Promise { <state>: "fulfilled", <value>: "I get a book" }

The Promise constructor creates promises

You can use the Promise constructor to create promise objects.

Here's an example:

const myMomsPromise = new Promise(function (resolve, reject) {
resolve("I get a book");
});

// Check myMomsPromise's content:
console.log(myMomsPromise);

// The invocation above will return:
Promise { <state>: "fulfilled", <value>: "I get a book" }

The async keyword is a syntactic sugar

An async function is a syntactic sugar that simplifies the creation of promise objects. Therefore, you can still use it to create a promise chain.

Here's an example:

// Create an async function:
async function myMomsPromise() {
return "I get a book";
}

// Create a promise chain:
myMomsPromise()
.then((value) => value + " " + "and a car")
.then((value) => console.log(value))
.catch((e) => console.error(e));

// The invocation above will return:
// "I get a book and a car"

Try Editing It

So, now that we know what an async keyword does, let's discuss the await keyword.

What Is the await Keyword in JavaScript?

The await keyword instructs a function to wait for a promise to be settled before continuing its execution.

tip
  • Although the await keyword works only inside an async function in regular JavaScript code, you can use it at the top level of a JavaScript module.
  • You can use zero or more await expressions in an async function.

Example of an await Keyword in JavaScript

The await keyword in the snippet below instructs showMomsPromise to wait for myMomsPromise to be settled before continuing its execution.

async function showMomsPromise() {
const myMomsPromise = new Promise(function (resolve, reject) {
setTimeout(resolve, 5000, "I get a book");
});
console.log(await myMomsPromise);
}

// Invoke the showMomsPromise() asynchronous function:
showMomsPromise();

// The invocation above will first return:
// Promise { <state>: "pending" }

// Then, after 5000 milliseconds (5 seconds), the invocation will return:
// "I get a book"

What Happens If You Do Not Use an await Keyword in an Async Function?

Suppose you omit the await keyword in your asynchronous function. In that case, JavaScript will not wait for any pending promises. Instead, it will continue executing other code while expecting the resolution of pending promises.

Here's an example:

async function showMomsPromise() {
const myMomsPromise = new Promise(function (resolve, reject) {
setTimeout(resolve, 5000, 'I get a book');
});
console.log(myMomsPromise);
}

// Invoke the showMomsPromise() asynchronous function:
showMomsPromise();

// The invocation above will first return:
// Promise { <state>: "pending" }

// Immediately afterward, the invocation will return:
Promise { <state>: "fulfilled", <value>: undefined }

Omitting the await keyword in the snippet above caused the console.log() statement to invoke myMomsPromise immediately—without waiting for its promise to be resolved.

Consequently, showMomsPromise()'s invocation returned a fulfilled promise that JavaScript resolved with an undefined value.

Does an Async Function Always Return a Promise Object?

An async function will always return a promise—even if you do not return any value.

Example of an async function that does not return any value

async function showMomsPromise() {}

// Invoke the showMomsPromise() asynchronous function:
showMomsPromise();

// The invocation above will return:
Promise { <state>: "fulfilled", <value>: undefined }

The async function above returned a promise that JavaScript resolved with an undefined value because we did not explicitly tell it to return any item.

Example of an async function that logs items to the console

async function showMomsPromise() {
const myMomsPromise = await "I get a book";
console.log(myMomsPromise);
}

// Invoke the showMomsPromise() asynchronous function:
showMomsPromise();

// The invocation above will first return:
"I get a book"

// It will also return:
Promise { <state>: "fulfilled", <value>: undefined }

The async function in the snippet above returned a promise with an undefined value because we did not tell it to return any value. Instead, we only told it to log "I get a book" to the browser's console.

Example of an async function that returns a value

async function showMomsPromise() {
const myMomsPromise = await "I get a book";
console.log(myMomsPromise);
return myMomsPromise;
}

// Invoke the showMomsPromise() asynchronous function:
showMomsPromise();

// The invocation above will first return:
// "I get a book"

// It will also return:
Promise { <state>: "fulfilled", <value>: "I get a book" }

The async function above returned a promise object that JavaScript fulfilled with the function's returned value.

So, now that you know how the async and await keywords work, we can discuss how to convert a then() promise chain to an async/await code.

How to Convert a then() Promise Code to an Async/Await Program

Consider the following code:

// Create two variables:
let finalResponse = null;
const passedExam = true;

// Create a function that returns mom's first promise:
function emitFirstProm() {
return Promise.resolve("I get a book");
}

// Create a function that adds mom's first promise to her second one:
function emitSecondProm(firstPromise) {
return Promise.resolve(firstPromise + ", a phone");
}

// Create a function that adds mom's previous promises to her third one:
function emitThirdProm(pastProms) {
return Promise.resolve(pastProms + ", a laptop");
}

// Create a function that add mom's previous promises to her fourth one:
function emitFourthProm(pastProms) {
return Promise.resolve(pastProms + ", and a Jeep 🤩🎉✨");
}

// Create mom's promise:
const myMomsPromise = new Promise(function (resolve, reject) {
if (passedExam) {
resolve(emitFirstProm());
} else {
reject("You did not pass your exam, so mom rejected her promise.");
}
});

// Invoke each of the functions above asynchronously by attaching them to myMomsPromise object:
myMomsPromise
.then(emitSecondProm)
.then(emitThirdProm)
.then(emitFourthProm)
.then(function (value) {
finalResponse = `Mom fulfilled her promise! ${value}`;
})
.catch(function (e) {
console.error(`Oops! Caught the following error: ${e}`);
})
.finally(function () {
console.log(finalResponse);
});

// The invocation above will return:
// "Mom fulfilled her promise! I get a book, a phone, a laptop, and a Jeep 🤩🎉✨"

Try Editing It

The snippet above used a chain of then() methods to attach callbacks to the myMomsPromise object. You can simplify the code by replacing the then() blocks with async/await like so:

// Create two variables:
let finalResponse = null;
const passedExam = true;

// Create a function that returns mum's first promise:
async function emitFirstProm() {
return "I get a book";
}

// Create a function that adds mum's first promise to her second one:
async function emitSecondProm(firstPromise) {
return firstPromise + ", a phone";
}

// Create a function that adds mum's previous promises to her third one:
async function emitThirdProm(pastProms) {
return pastProms + ", a laptop";
}

// Create a function that adds mum's previous promises to her fourth one:
async function emitFourthProm(pastProms) {
return pastProms + ", and a Jeep 🤩🎉✨";
}

// Create mom's promise:
const myMomsPromise = async function () {
if (passedExam) {
const firstPromise = await emitFirstProm();
const secondPromise = await emitSecondProm(firstPromise);
const thirdPromise = await emitThirdProm(secondPromise);
const fourthPromise = await emitFourthProm(thirdPromise);
finalResponse = `Mom fulfilled her promise! ${fourthPromise}`;
} else {
throw new Error("You did not pass your exam, so mom rejected her promise.");
}
};

// Invoke the myMomsPromise async function:
myMomsPromise()
.catch(function (e) {
console.error(`Oops! Caught the following error: ${e}`);
})
.finally(function (e) {
console.log(finalResponse);
});

// The invocation above will return:
// "Mom fulfilled her promise! I get a book, a phone, a laptop, and a Jeep 🤩🎉✨"

Try Editing It

The snippet above used the await keyword before each asynchronous function call rather than creating a chain of then() blocks. Afterward, we assigned the returned promise objects to the firstPromise, secondPromise, thirdPromise, and fourthPromise variables, respectively.

note

Each await keyword instructs myMomsPromise to pause its execution until the keyword's function call returns its result. Therefore, all subsequent code after the paused line will not execute until the await function call returns its value.

To optimize your code, you can also use a hybrid of the then() block and the async/await keywords.

Here's an example:

// Create two variables:
let finalResponse = null;
const passedExam = true;

// Create a function that returns mum's first promise:
const emitFirstProm = async () => "I get a book";

// Create a function that adds mum's first promise to her second one:
const emitSecondProm = async (firstPromise) => firstPromise + ", a phone";

// Create a function that adds mum's previous promises to her third one:
const emitThirdProm = async (pastProms) => pastProms + ", a laptop";

// Create a function that adds mum's previous promises to her fourth one:
const emitFourthProm = async (pastProms) => pastProms + ", and a Jeep 🤩🎉✨";

// Create mom's promise:
const myMomsPromise = async function () {
if (passedExam) {
const firstPromise = await emitFirstProm();
const secondPromise = await emitSecondProm(firstPromise);
const thirdPromise = await emitThirdProm(secondPromise);
const fourthPromise = await emitFourthProm(thirdPromise);
return `Mom fulfilled her promise! ${fourthPromise}`;
} else {
throw new Error("You did not pass your exam, so mom rejected her promise.");
}
};

// Invoke the myMomsPromise async function:
myMomsPromise()
.then((value) => (finalResponse = value))
.catch((e) => console.error(`Oops! Caught the following error: ${e}`))
.finally(() => console.log(finalResponse));

// The invocation above will return:
// "Mom fulfilled her promise! I get a book, a phone, a laptop, and a Jeep 🤩🎉✨"

Try Editing It

The snippet above made myMomsPromise a pure function by returning its value and using a then() block to manage it.

CodeSweetly ads

Express Your Love for Coding!

Explore CodeSweetly's Shop for an array of stylish products to enhance your coding experience.
Shop now

How Does an Async Function's Execution Order Work?

Consider the following MDN's statements:

The body of an async function can be thought of as being split by zero or more await expressions.

Top-level code, up to and including the first await expression (if there is one), is run synchronously. In this way, an async function without an await expression will run synchronously.

If there is an await expression inside the function's body, however, the async function will always complete asynchronously.

Code after each await expression can be thought of as existing in a .then callback. In this way a promise chain is progressively constructed with each reentrant step through the function. The return value forms the final link in the chain.

MDN

Let's use an example to understand the above statements.

Example of How an Async Function's Execution Order Works

Consider this snippet below:

function myMomsPromise() {
console.log("Starting mom's promise check...");
return new Promise((resolve) => {
setTimeout(function () {
resolve("I get a book.");
console.log("Mom's promise is fulfilled!");
}, 5000);
});
}

function myDadsPromise() {
console.log("Starting dad's promise check...");
return new Promise((resolve) => {
setTimeout(function () {
resolve("I get a pen.");
console.log("Dad's promise is fulfilled!");
}, 1000);
});
}

async function checkMomAndDadsPromises() {
console.log("===Promises confirmation check started===");

const momsPromiseResponse = await myMomsPromise();
console.log(momsPromiseResponse);

const dadsPromiseResponse = await myDadsPromise();
console.log(dadsPromiseResponse);
}

function startPromiseChecks() {
checkMomAndDadsPromises();
console.log("I prayed while waiting for mom's promise.");
console.log("Mom's promise is worth waiting for.");
setTimeout(() => console.log("Is mom's promise still pending?"), 5100);
}

startPromiseChecks();

Here's what we did in the snippet above:

  1. We use a regular function (startPromiseChecks) to run an asynchronous function (checkMomAndDadsPromises)
  2. We programmed the checkMomAndDadsPromises asynchronous function to await two promises (myMomsPromise and myDadsPromise).

When startPromiseChecks() is running, in what order would its statements execute? Let's find out.

  1. startPromiseChecks will first invoke the checkMomAndDadsPromises async function.
  2. checkMomAndDadsPromises will start its execution synchronously until it reaches its first await expression's pending promise.
  3. On getting to its first await expression, checkMomAndDadsPromises will:
    1. Log "===Promises confirmation check started===" and "Starting mom's promise check..." to the browser's console.
    2. Wait for myMomsPromise's resolution—while also yielding control back to startPromiseChecks (the function that invoked checkMomAndDadsPromises).
  4. While awaiting myMomsPromise's settlement, startPromiseChecks—which now has the control—will continue executing its code.
  5. After a while (5000 milliseconds), when myMomsPromise gets settled, checkMomAndDadsPromises will regain control. Therefore, it will:
    1. Assign the first await expression's resolution to momsPromiseResponse.
    2. Log the momsPromiseResponse's value to the browser's console.
    3. Evaluates its second await expression
    4. Log "Starting dad's promise check..." to the browser's console.
    5. Wait for myDadsPromise's resolution—while also yielding control back to startPromiseChecks (the function that invoked checkMomAndDadsPromises).
  6. While awaiting myDadsPromise's settlement, startPromiseChecks—which now has the control—will continue executing its code.
  7. After a while (1000 milliseconds), when myDadsPromise gets settled, checkMomAndDadsPromises will regain control. Therefore, it will:
    1. Assign the second await expression's resolution to dadsPromiseResponse.
    2. Log the dadsPromiseResponse's value to the browser's console.

After logging dadsPromiseResponse's value to the browser's console, if any return expression exists inside the checkMomAndDadsPromises function, the computer will yield control to the expression. However, none exist in our case, so startPromiseChecks()'s invocation output will look like this:

===Promises confirmation check started===
Starting mom's promise check...
I prayed while waiting for mom's promise.
Mom's promise is worth waiting for.
undefined
Mom's promise is fulfilled!
I get a book.
Starting dad's promise check...
Is mom's promise still pending?
Dad's promise is fulfilled!
I get a pen.

Try Editing It

Join CodeSweetly's Substack