Promises
Handling Promise objects
fetch
calls are asynchronous and they return Promise objects.- A promise is an object representing the completion of an asynchronous operation in future: the operation either succeeds (fulfilled) of fails (rejected).
- The end result of a promise is not immediately available, and we do not know if the operation will succeed or not, nor do we know when it will be available.
- For that reason, promise objects need special handling:
- The handling needs to be launched when the value of the promise is available
- We need to handle both successful results as well as failures
- JavaScript provides two ways to handle promises
then-catch
- Promises can be handled using the Promise
then
andcatch
methods:
fetch('https://mydomain.com/api')
.then(response => response.json()) // handle Promise success, handling returns Promise
.then(data => { // handle the latter Promise
// process response
})
.catch(error => console.error(error)); // handle failures
- When the promise resolves successfully, the result is passed as an argument to the handler function in the
then
call. then
calls can be chained; the previous handler returns another promise.- If the promise fails or there is any other error during the handling, the handler function passed in the
catch
is called.
async-await
- ECMAScript 2017 added a new syntax for handling Promise objects.
- The purpose of the addition was to make asynchronous code easier to write and to read afterwards by making async code look more like old-school synchronous code.
async
keyword put in front of a function declaration makes the function return a Promise instead of returning the value directlyawait
can be put in front of any async function call to pause your code on that line until the promise fulfills, then return the resulting value- Errors are handled as exceptions, that is using
try-catch
blocks
async-await example
fetchData = async () => {
try {
// execution is paused until the fetch call result is available
const response = await fetch('https://mydomain.com/api');
// execution is paused until the json call result is available
const data = await response.json();
}
catch(error) { // any error results in exception, handled here
console.error(error);
}
}
- asynchronous code is within a
try
block. If any failure occurs, it will be handled in thecatch
handler - Note:
await
only works insideasync
functions! Even though the code looks like synchronous it is still asynchronous.
Using async-await in React code
- Both syntaxes are equally valid and usable, you can use either.
- Note that the function passed to
useEffect
may not beasync
. - If you need to call an async function with useEffect, pass it a sychronous function that calls your asynchronous function, e.g.
useEffect(() => { // regular non-async function passed to useEffect
// define async function that makes the asyncronous calls
const doFetch = async () => {
const result = await fetchData(); // call my async function
setData(result);
};
// call the async function
doFetch();
}, []);
Immediate invokation
- You can do the same as previously also using immediate invokation (calling) of the newly declared function:
useEffect(() => { // regular non-async function passed to useEffect
// define async function expression that makes the asynchronous calls...
(async () => {
const result = await fetchData(); // call my async function
setData(result);
})(); // ...and call it immediately
}, []);
- Because the precedence of the function call operator
()
is so high, the function expression (arrow function) needs to be in brackets