async
functions do not replace the Promise
type; they add language keywords that make promises easier to call. They are interchangeable:
async function doAsyncThing() { ... }
function doPromiseThing(input) { return new Promise((r, x) => ...); }
// Call with promise syntax
doAsyncThing()
.then(a => doPromiseThing(a))
.then(b => ...)
.catch(ex => ...);
// Call with await syntax
try {
const a = await doAsyncThing();
const b = await doPromiseThing(a);
...
}
catch(ex) { ... }
Any function that uses chains of promises can be rewritten using await
:
function newUnicorn() {
return fetch('unicorn.json') // fetch unicorn.json from server
.then(responseCurrent => responseCurrent.json()) // parse the response as JSON
.then(unicorn =>
fetch('new/unicorn', { // send a request to 'new/unicorn'
method: 'post', // using the POST method
body: JSON.stringify({unicorn}) // pass the unicorn to the request body
})
)
.then(responseNew => responseNew.json())
.then(json => json.success) // return success property of response
.catch(err => console.log('Error creating unicorn:', err));
}
The function can be rewritten using async
/ await
as follows:
async function newUnicorn() {
try {
const responseCurrent = await fetch('unicorn.json'); // fetch unicorn.json from server
const unicorn = await responseCurrent.json(); // parse the response as JSON
const responseNew = await fetch('new/unicorn', { // send a request to 'new/unicorn'
method: 'post', // using the POST method
body: JSON.stringify({unicorn}) // pass the unicorn to the request body
});
const json = await responseNew.json();
return json.success // return success property of response
} catch (err) {
console.log('Error creating unicorn:', err);
}
}
This async
variant of newUnicorn()
appears to return a Promise
, but really there were multiple await
keywords. Each one returned a Promise
, so really we had a collection of promises rather than a chain.
In fact we can think of it as a function*
generator, with each await
being a yield new Promise
. However, the results of each promise are needed by the next to continue the function. This is why the additional keyword async
is needed on the function (as well as the await
keyword when calling the promises) as it tells Javascript to automatically creates an observer for this iteration. The Promise
returned by async function newUnicorn()
resolves when this iteration completes.
Practically, you don't need to consider that; await
hides the promise and async
hides the generator iteration.
You can call async
functions as if they were promises, and await
any promise or any async
function. You don't need to await
an async function, just as you can execute a promise without a .then()
.
You can also use an async
IIFE if you want to execute that code immediately:
(async () => {
await makeCoffee()
console.log('coffee is ready!')
})()