Skip to content

Commit 6d7df22

Browse files
committed
multiple API call to execute sequentially with Promise
1 parent feb712a commit 6d7df22

8 files changed

+146
-5
lines changed

Javascript/Promise-master-notes/How-Promise-makes-code-Asynchronous-non-blocking.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Understanding how Promise makes code Asynchronous / non-blocking by understanding how Fetch API works
1+
### Understanding how Promise makes code Asynchronous / non-blocking by understanding how Fetch API works
22

3-
## Key Point - With the .then() method, we can chain our ASYNCHRONOUS calls in a SYNCHRONOUS manner. So, within the Promise block, I am converting few Asynchronous operations to Synchronous ones.
3+
#### Key Point - With the .then() method, we can chain our ASYNCHRONOUS calls in a SYNCHRONOUS manner. So, within the Promise block, I am converting few Asynchronous operations to Synchronous ones.
44

55
## And during that time when those Synchronous operations are getting executed, whatever is after the chain of methods inside the Promise-related block, gets executed normally without being blocked or having to wait for them, while I wait for some execution ( e.g. waiting for response from an API) to happen within the Promise’s block of codes.
66

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Promise object is used for handling asynchronous computations which has some important guarantees that are difficult to handle with the callback method (the more old-school method of handling asynchronous code).
2+
3+
A Promise object is simply a wrapper around a value that may or may not be known when the object is instantiated and provides a method for handling the value after it is known (also known as resolved) or is unavailable for a failure reason (we'll refer to this as rejected).
4+
5+
Using a Promise object gives us the opportunity to associate functionality for an asynchronous operation's eventual success or failure (for whatever reason). It also allows us to treat these complex scenarios by using synchronous.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Lets say I have this
2+
3+
```js
4+
this.getList();
5+
this.getServers();
6+
this.getCredentials();
7+
console.log("waited");
8+
```
9+
10+
### What would be a way to console.log only after the other 3 finished? and those 3 are actually API calls.
11+
12+
Solution -
13+
14+
```js
15+
Promise.all([this.getList(), this.getServers(), this.getCredentials()]).then(
16+
() => console.log("waited")
17+
);
18+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#### 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.
2+
3+
#### 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.
4+
5+
[I have not tested this code yet in an actual app]
6+
7+
```js
8+
// Refactor getStudents and getScores to return Promise for their response bodies
9+
function getStudents() {
10+
return fetch(`api/students`, {
11+
headers: {
12+
"Content-Type": "application/json",
13+
Accept: "application/json"
14+
}
15+
}).then(response => response.json());
16+
}
17+
18+
function getScores() {
19+
return fetch(`api/scores`, {
20+
headers: {
21+
"Content-Type": "application/json",
22+
Accept: "application/json"
23+
}
24+
}).then(response => response.json());
25+
}
26+
27+
// Request both students and scores in parallel and return a Promise for both values.
28+
// `Promise.all` returns a new Promise that resolves when all of its arguments resolve.
29+
function getStudentsAndScores() {
30+
return Promise.all([getStudents(), getScores()]);
31+
}
32+
33+
// When this Promise resolves, both values will be available. And because getStudentsAndScores() returns a Promise, I can chain a .then() function to it.
34+
getStudentsAndScores().then(([students, scores]) => {
35+
// both have loaded!
36+
console.log(students, scores);
37+
});
38+
```
39+
40+
In this approach I make both requests at the same time.
41+
42+
#### Source
43+
44+
[https://stackoverflow.com/questions/44980247/how-to-finish-all-fetch-before-executing-next-function-in-react](https://stackoverflow.com/questions/44980247/how-to-finish-all-fetch-before-executing-next-function-in-react)
Loading

Javascript/sequential-execution-of-codes/sequential-execution-async-await.md renamed to Javascript/sequential-execution-of-codes-React-Node-Context/sequential-execution-async-await-in-Express-routes.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
### Use case (Sequential Execuetion with plain callback function and async-await) - Here in the below EDIT / PUT route - From Client side req.body, I am sending a JSON data which along with other info has a 'date' field. I had to format that 'date' from req.body (to "YYYY-MM-DD") with moment, before running findByIdAndUpdate(). Else mongoose was saving the date one day prior to what I was selecting in the DatePicker, and then subsequent API call for that date's data (after the EDIT) will NOT give me the correct edited data.
1+
### Use case (Sequential Execution with plain callback function and async-await) - Here in the below EDIT / PUT route - From Client side req.body, I am sending a JSON data which along with other info has a 'date' field. I had to format that 'date' from req.body (to "YYYY-MM-DD") with moment, before running findByIdAndUpdate(). Else mongoose was saving the date one day prior to what I was selecting in the DatePicker, and then subsequent API call for that date's data (after the EDIT) will NOT give me the correct edited data.
22

33
### NOTE - The code is working EVEN WITHOUT async-await. But including async-await seems to be better for safely achieving the result.
44

@@ -15,7 +15,9 @@
1515
}
1616
```
1717

18-
### The acutal route code in Express backend
18+
### The actual route code in Express backend
19+
20+
#### Alternative - 1 - With a wrapper function which will invoke a callback()
1921

2022
```js
2123
router.put("/:id", (req, res, next) => {
@@ -45,7 +47,7 @@ router.put("/:id", (req, res, next) => {
4547
});
4648
```
4749

48-
#### Alternative - 1 for the above EDIT (PUT) route function (with an extra database call ) - this code was working
50+
#### Alternative - 2 for the above EDIT (PUT) route function (with an extra database call ) - this code was working
4951

5052
```js
5153
router.put("/:id", (req, res, next) => {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
JavaScript is single threaded, that means only one statement is executed at a time. As the JS engine processes our script line by line, it uses this single Call-Stack to keep track of codes that are supposed to run in their respective order. Like what a stack does, a data structure which records lines of executable instructions and executes them in LIFO manner. So say if the engine steps into a function foo(){ it PUSH-es foo() into the stack and when the execution of foo()return; } is over foo() is POP-ped out of the call-stack.
2+
3+
<img src="./sequential-execution-1.png">
4+
5+
EXERCISE 1: So from the above diagram shows how a typical line by line execution happens. When the script of three console.log() statements is thrown at JS — 
6+
Step 1: The console.log("Print 1")is pushed into the call stack and executed, once done with execution, it is then popped out of the stack. Now the stack is empty and ready for any next instruction to be executed.
7+
Step 2: console.log("Print 2"); // is the next instruction is pushed and the same thing repeats until - Step 3: is executed and there is nothing left to push and execute.
8+
9+
#### Further Reading
10+
11+
https://medium.com/@siddharthac6/javascript-execution-of-synchronous-and-asynchronous-codes-40f3a199e687
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
### A specific Use Case -
2+
3+
Here in the below backend Express Route - I have to capture visitor data (after OTP was sent and OTP Mongodb schema updated with that latest OTP) when a visitor to the site downloads data.
4+
5+
But I need to first pick the latest OTP (that was generated and saved in mongodb) from the already saved database before comparing with the otp input by the user when prompted.
6+
7+
```js
8+
router.route("/visitor/:id").put((req, res, next) => {
9+
let visitorData = req.body;
10+
let visitorEmail = req.body.company_email;
11+
let latestOtp = [];
12+
13+
// Wrapper function that will wrap the database call (the find() query) in a function and pass it a callback function that gets executed after the database query has finished.
14+
// Also always make sure the callback is indeed a function, without this check, if the findLatestOTP() is called either without the callback function as a parameter OR in place of a function a non-function is passed, our code will result in a runtime error.
15+
function findLatestOTP(mongoCollection, callback) {
16+
mongoCollection
17+
.find({ visitor_email: visitorEmail })
18+
.limit(1)
19+
.sort({ createdAt: -1 })
20+
.exec((err, record) => {
21+
if (err) {
22+
console.log(err);
23+
} else {
24+
latestOtp.push(record[0].generated_otp);
25+
if (typeof callback === "function") {
26+
callback();
27+
}
28+
}
29+
});
30+
}
31+
32+
findLatestOTP(OTP, function() {
33+
if (req.body.otpReceivedByVisitor !== latestOtp[0]) {
34+
return res
35+
.status(401)
36+
.send({ success: false, msg: "Incorrect Code was input" });
37+
} else {
38+
DOCUMENTMODAL.findById(req.params.id, (err, record) => {
39+
if (err) {
40+
console.log(err);
41+
}
42+
record.visitor.push(visitorData);
43+
record.save((err, updatedRecord) => {
44+
if (err) {
45+
return next(err);
46+
}
47+
res.status(200).send(updatedRecord);
48+
});
49+
});
50+
}
51+
});
52+
});
53+
```
54+
55+
#### Some related Explanation -
56+
57+
##### JavaScript is single threaded, that means only one statement is executed at a time. As the JS engine processes our script line by line, it uses this single Call-Stack to keep track of codes that are supposed to run in their respective order.
58+
59+
Like what a stack does, a data structure which records lines of executable instructions and executes them in LIFO manner. So say if the engine steps into a function foo(){ it PUSH-es foo() into the stack and when the execution of foo()return; } is over foo() is POP-ped out of the call-stack.
60+
61+
<img src="./sequential-execution-1.png">

0 commit comments

Comments
 (0)