async/await
async & await
"Async/await" gives you a somewhat different, yet simpler way to implement asynchronous promise-based JavaScript.
In the next example a fetch is "rewritten" using the async
and await
keywords:
fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json')
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return response.json();
})
.then((data) => {
console.log(data[0].name);
})
.catch((error) => {
console.error(error);
});
// logs: "baked beans"
async function fetchProductName(nr) {
try {
const response = await fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const data = await response.json();
console.log(data[nr].name);
}
catch (error) {
console.error(error);
}
};
fetchProductName(0); // logs: "baked beans"
fetchProductName(2); // logs: "spam"
Now we wrap the promise chain that handles multiple subsequent asynchronous functions that depend on each other, in a function.
With keyword async
before the function declaration we make it an asynchronous function.
This means that the function returns a promise (not used in the above example) which resolves with the value returned by the async function,
or rejects with an exception thrown from the async function. To demonstrate this: the next function does the same as the above function only now
the function returns a promise that resolves with the product name, instead of logging the name to the console from within the function.
async function fetchProductName(nr) {
try {
const response = await fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const data = await response.json();
return data[nr].name; // returns the product name, resolving the overall promise
}
catch (error) {
console.error(error);
}
};
fetchProductName(0).then(name => console.log(name)); // logs: "baked beans"
fetchProductName(2).then(name => console.log(name)); // logs: "spam"
// Next will not work!
// The function does not return a string, but a promise.
console.log(fetchProductName(2).length); // logs: undefined
The biggest difference may be the way the promise chain in the function is set up. This is done by use of the keyword await
.
Keyword await
can only be used inside an async
function. That is why we wrapped the promise chain in a function and not just used a
mere try...catch
statement.
The await
is placed directly before a promise (or before a call to a function that returns a promise).
This makes JavaScript pause function execution at that point until the promise is settled, at which point the resolution value or the rejection error is returned.
In the example above, the returns are assigned to a constant.
So, unlike then()
, await
does not return a new promise; it directly returns the value (or error) the awaited promise resolves (or rejects) with.
When a promise in the asynchronous function becomes rejected it throws an error.
In case of such error, or when a explicit error (via a throw
statement) occurs, the control jumps to the catch block.
However, it is not mandatory to use try...catch
inside the asynchronous function. When something throws an error inside the function, the promise returned
by the function becomes rejected. This error can be handled by asyncFunction().catch(/* handle error */)
outside the function.
The methods to handle sets of promises, like Promise.all()
, also work with async/await:
async function fetchResources() {
try {
const responses = await Promise.all([
fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json'),
fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/not-found'),
fetch('https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json')
]);
for (const response of responses) {
if (!response.ok) {
throw new Error(`Error in network response: ${response.status} for fetch ${response.url}`);
}
}
for (const response of responses) {
console.log(`${response.url}`);
}
}
catch (error) {
console.error(`Failed to fetch: ${error}`)
}
};
fetchResources();