Async Functions and await
Version: ES2017
Level: Intermediate
Async (i.e. asynchronous) functions are a fairly new kind of function type in JavaScript that allow you to use the await
operator. The await
operator (which currently is only available in async functions) is used to obtain the result of a promise, pausing the current execution context until the value of that promise is available. Once it is, the await
expression resolves to that value and execution continues. Other code around the async function call is free to continue running when this pause happens which is exactly what makes async functions async.
To create an async function, include the async
keyword before the function definition. They’re called just like any other function.
async function getFlightStatus () {
console.log('Starting to get status...');
let flightStatus = await Promise.resolve('Delayed');
console.log('Got status!');
return flightStatus;
}
console.log('Before');
getFlightStatus();
console.log('After');
/* logs:
Before
Starting to get status...
After
Got status!
*/
Here, you can see that once the await
in the getFlightStatus()
function was reached, the function execution paused and code at its callsite continued to run. This is why the “After” log came before the “Got status!” log.
Because async functions can pause, they will always return a promise. This promise will resolve to the return value of the async function once the async function eventually returns.
let result = getFlightStatus();
console.log(result instanceof Promise); // true
result.then(status => {
console.log(status); // Delayed
});
Like normal functions, if an async function doesn’t have an explicit return, it will implicitly return undefined
. In that case, when called it will return a promise which will resolve to undefined
.
async function getFlightRefund () {
// does not return
}
getFlightRefund().then(refund => {
console.log(refund); // undefined
});
Using await
in async functions is a nice alternative to using the promise API. It lets you write asynchronous promise code much like you would write normal synchronous code. await
itself replaces the use of then()
while try...catch...finally
blocks replace the use of catch()
and finally()
in promises.
let somePromise = Promise.resolve('I promise');
async function awaitPromise () {
try {
let promiseValue = await somePromise;
console.log(promiseValue); // I promise
} catch (error) {
console.error(error.message);
} finally {
console.log('Done awaiting promise');
}
}
awaitPromise();
This is basically the same as
let somePromise = Promise.resolve('I promise');
somePromise.then(promiseValue => {
console.log(promiseValue); // I promise
}).catch(error => {
console.error(error.message);
}).finally(() => {
console.log('Done awaiting promise');
});
While you can currently only use await
inside async function, there is a stage 3 proposal for using await
in the top level scopes in modules. This would mean in the future, you could await promises without having to wrap them in an async function first (assuming you’re in a module).
More info: