Transform the following code with sequential execution. I want to fire second request based on one value returned by the first request.
For example, the Fetch API provides an interface for making network requests, returning Promises for us to resolve. To use it to get the current weather in Long Beach, we chain together two then callbacks:
fetch("https://api.com/values/1")
.then(response => response.json())
.then(json => console.log(json));
In the first, we create a callback function to receive the Response object and return back its JSON data. In the second, we create a callback that receives that data and then logs it to the console.
Need to wrap it inside an async function to make the async-await mechanism work.
const request = async () => {
const response = await fetch("https://api.com/values/1");
const json = await response.json();
console.log(json);
};
request();
In the first line, we make a GET request to https://api.com/values/1. Instead of continuing to the next line, we wait for the request to finish, hence await. When it finishes, it passes the resolved value to the response variable.
In the second line, we get the JSON version of the response. Again, we use await so we can wait for it to complete (or fail) and then pass the result to the json variable.
By wrapping the logic inside an async function, we can replace the then callbacks with await statements. The effect, the code pauses execution on those lines until the Promises resolve! Asynchronous programming becomes synchronous!
Async/Await enables us to write asynchronous code in a synchronous fashion, which produces cleaner and easier-to-understand logic. Under the hood, it’s just syntactic sugar using generators and yield statements to “pause” execution. In other words, async functions can “pull out” the value of a Promise even though it’s nested inside a callback function, giving us the ability to assign it to a variable!
1st Basic Implementation
handleForm = async event => {
this.setState({ isProcessing: true });
const response = await client.sendApiRequest({
value1: event.target.elements.field1.value,
value2: event.target.elements.field2.value
});
if (response.ok) this.setState({ isProcessing: false });
};
the code above is totally fine. The syntactic sugar of async/await is backed by Promises which means we could also look at our code as doing something like this:
handleForm = event => {
this.setState({ isProcessing: true });
client.sendApiRequest({
value1: event.target.elements.field1.value,
value2: event.target.elements.field2.value,
}).then(response => {
if (response.ok)
this.setState({ isProcessing: false });
});
});
}
The first part of that promise is going to execute in what is essentially a synchronous manner. That means we are safe to pass the event values as arguments.
However, it’s important to recognize that this does not mean that accessing the event values anywhere in an async function is okay. Take for example what would happen if we needed access the event after the API request.
handleForm = async event => {
this.setState({ isProcessing: true });
const response = await client.sendApiRequest({
value1: event.target.elements.field1.value,
value2: event.target.elements.field2.value
});
if (response.ok) {
this.setState({
isProcessing: false,
value1: event.target.elements.field1.value,
value2: event.target.elements.field2.value
});
}
};
Now we’re accessing the event after the await, which is like accessing it in the .then chain of a promise. We would be accessing the event asynchronously now.
Here’s that same event written as promises again:
handleForm = event => {
return new Promise((resolve, reject) => {
this.setState({ isProcessing: true });
client
.sendApiRequest({
value1: event.target.elements.field1.value,
value2: event.target.elements.field2.value
})
.then(response => {
if (response.ok) {
this.setState({
isProcessing: false,
value1: event.target.elements.field1.value,
value2: event.target.elements.field2.value
});
}
});
});
};
Problem - It a common requirement in React to sequentially execute codes ONLY after multiple API calls have given their result to the component. Here, I have two different API points that I am trying to get and restructure after getting the data : students and scores. They are both an array of objects.So the goal is : first, get students and scores, and second, with students and scores saved in state, I will modify them and create a new state based on students and scores state. In short, I have 3 functions: getStudents, getScores, and rearrangeStudentsAndScores. getStudents and getScores need to finish before rearrangeStudentsAndScores can run.
[I have not tested this code yet in an actual app]
// Refactor getStudents and getScores to return Promise for their response bodies
function getStudents() {
return fetch(`api/students`, {
headers: {
"Content-Type": "application/json",
Accept: "application/json"
}
}).then(response => response.json());
}
function getScores() {
return fetch(`api/scores`, {
headers: {
"Content-Type": "application/json",
Accept: "application/json"
}
}).then(response => response.json());
}
// Request both students and scores in parallel and return a Promise for both values.
// `Promise.all` returns a new Promise that resolves when all of its arguments resolve.
function getStudentsAndScores() {
return Promise.all([getStudents(), getScores()]);
}
// When this Promise resolves, both values will be available. And because getStudentsAndScores() returns a Promise, I can chain a .then() function to it.
getStudentsAndScores().then(([students, scores]) => {
// both have loaded!
console.log(students, scores);
});
In this approach I make both requests at the same time.
Source
Further Reading
1> https://medium.com/@ian.mundy/async-event-handlers-in-react-a1590ed24399 2> https://medium.com/@tkssharma/writing-neat-asynchronous-node-js-code-with-promises-async-await-fa8d8b0bcd7c – Very Good