Skip to content

Commit 9c9fa79

Browse files
committed
convert callback to async-await directly
1 parent 44289a2 commit 9c9fa79

File tree

2 files changed

+215
-1
lines changed

2 files changed

+215
-1
lines changed
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Converting to a Promise-based function is actually pretty simple. Look at the be
7676

7777
<img src="convert-callback-to-promise-async-await-1.png">
7878

79-
First, we remove the callback argument. Then we add the code to return a new Promise from our Promise-based function. The error callback becomes a reject, while the "happy path" callback becomes a resolve.
79+
First, we remove the callback argument. Then we add the code to return a new Promise from our Promise-based function. The error callback becomes a reject, while the "happy path" callback becomes a resolve. Promise returning functions should never throw, they should return rejections instead. Throwing from a promise returning function will force you to use both a } catch { and a .catch. People using promisified APIs do not expect promises to throw.
8080

8181
Remember, Promise expects a single function as an argument. That function takes 2 arguments (both are callbacks), a resolve function and a reject function.
8282

@@ -151,3 +151,5 @@ Note that async functions all return Promises, so when you use return you are ju
151151
1> https://benmccormick.org/2015/12/30/es6-patterns-converting-callbacks-to-promises
152152

153153
2> https://dev.to/ccleary00/how-to-rewrite-a-callback-function-in-promise-form-and-asyncawait-form-in-javascript-410e
154+
155+
3> https://medium.com/front-end-weekly/callbacks-promises-and-async-await-ad4756e01d90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
Let’s say you have a function that will print a string after a random amount of time: And I am defining that random unit of time with `Math.floor(Math.random() * 100) + 1)`
2+
3+
#### Function without callback implementation
4+
5+
```js
6+
function printString(string) {
7+
setTimeout(() => {
8+
console.log(string);
9+
}, Math.floor(Math.random() * 100) + 1);
10+
}
11+
```
12+
13+
Let’s try to print the letters A, B, C in that order:
14+
15+
```js
16+
function printAll() {
17+
printString("A");
18+
printString("B");
19+
printString("C");
20+
}
21+
printAll();
22+
```
23+
24+
You will notice that A, B, and C print in a different and random order each time you call printAll!
25+
26+
This is because these functions are asynchronous. Each function gets executed in order, but each one is independent with it’s own setTimeout. They won’t wait for the last function to finish before they start.
27+
28+
This is super annoying, so let’s fix it with a callback.
29+
30+
#### Function with callback implementation
31+
32+
A callback is a function that is passed to another function. When the first function is done, it will run the second function.
33+
34+
```js
35+
function printString(string, callback) {
36+
setTimeout(() => {
37+
console.log(string);
38+
callback();
39+
}, Math.floor(Math.random() * 100) + 1);
40+
}
41+
```
42+
43+
Again, let’s try to print the letters A, B, C in that order:
44+
45+
```js
46+
function printAll() {
47+
printString("A", () => {
48+
printString("B", () => {
49+
printString("C", () => {});
50+
});
51+
});
52+
}
53+
printAll();
54+
```
55+
56+
Well, the code is a lot uglier now, and I have created a callback-hell, but at least it works! Each time you call printAll, you get the same result. Promises to the rescue.
57+
58+
### Promise implementation
59+
60+
```js
61+
function printString(string) {
62+
return new Promise((resolve, reject) => {
63+
setTimeout(() => {
64+
console.log(string);
65+
resolve();
66+
}, Math.floor(Math.random() * 100) + 1);
67+
});
68+
}
69+
```
70+
71+
So, just following the standard conversion technique from callback to Promise, wrap the whole function in a Promise, and instead of calling the callback, you call resolve (or reject if there is an error). The function returns this Promise object.
72+
73+
Again, let’s try to print the letters A, B, C in that order:
74+
75+
```js
76+
function printAll() {
77+
printString("A")
78+
.then(() => {
79+
return printString("B");
80+
})
81+
.then(() => {
82+
return printString("C");
83+
});
84+
}
85+
printAll();
86+
```
87+
88+
By using features of arrow functions, we can remove the “wrapper” function. The code becomes cleaner, but still has a lot of unnecessary parenthesis:
89+
90+
```js
91+
function printAll() {
92+
printString("A")
93+
.then(() => printString("B"))
94+
.then(() => printString("C"));
95+
}
96+
printAll();
97+
```
98+
99+
### Async-Await implementation
100+
101+
Await is basically syntactic sugar for Promises. It makes your asynchronous code look more like synchronous/procedural code, which is easier for humans to understand.
102+
103+
The printString function need to remain the same, as above in the promise version. Because **Await works only with Promises, it does not work with callbacks. So to implement async-await to a function/code, I first have to convert the callback to a Promise **
104+
105+
Again, let’s try to print the letters A, B, C in that order:
106+
107+
```js
108+
async function printAll() {
109+
await printString("A");
110+
await printString("B");
111+
await printString("C");
112+
}
113+
printAll();
114+
```
115+
116+
### Now pass output of one function to the next function
117+
118+
The printString function doesn’t return anything and is independent, all we cared about was the order. But what if you wanted to take the output of the first function, do something with it in the second function, and then pass it to the third function?
119+
120+
Instead of printing the string each time, let’s make a function that will concatenate the string and pass it on.
121+
122+
### Callbacks Implementation
123+
124+
```js
125+
function addString(previous, current, callback) {
126+
setTimeout(() => {
127+
callback(previous + " " + current);
128+
}, Math.floor(Math.random() * 100) + 1);
129+
}
130+
131+
// And in order to call it:
132+
133+
function addAll() {
134+
addString("", "A", result => {
135+
addString(result, "B", result => {
136+
addString(result, "C", result => {
137+
console.log(result); // Prints out " A B C"
138+
});
139+
});
140+
});
141+
}
142+
addAll();
143+
```
144+
145+
Not so nice.
146+
147+
### Promise Implementation
148+
149+
Here it is in Promise style. Again same standard conversion technique from callback to Promise, wrap the whole function in a Promise, and instead of calling the callback, you call resolve (or reject if there is an error). The function returns this Promise object.
150+
151+
```js
152+
function addString(previous, current) {
153+
return new Promise((resolve, reject) => {
154+
setTimeout(() => {
155+
resolve(previous + " " + current);
156+
}, Math.floor(Math.random() * 100) + 1);
157+
});
158+
}
159+
160+
// And in order to call it:
161+
162+
function addAll() {
163+
addString("", "A")
164+
.then(result => {
165+
return addString(result, "B");
166+
})
167+
.then(result => {
168+
return addString(result, "C");
169+
})
170+
.then(result => {
171+
console.log(result); // Prints out " A B C"
172+
});
173+
}
174+
addAll();
175+
```
176+
177+
Using arrow functions means we can make the code a little nicer:
178+
179+
```js
180+
function addAll() {
181+
addString("", "A")
182+
.then(result => addString(result, "B"))
183+
.then(result => addString(result, "C"))
184+
.then(result => {
185+
console.log(result); // Prints out " A B C"
186+
});
187+
}
188+
addAll();
189+
```
190+
191+
This is definitely more readable, especially if you add more to the chain, but still a mess of parenthesis.
192+
193+
### Async-Await Implementation
194+
195+
The function stays the same as the Promise version. Because **Await works only with Promises, it does not work with callbacks. So to implement async-await to a function/code, I first have to convert the callback to a Promise **
196+
197+
And in order to call it:
198+
199+
```js
200+
async function addAll() {
201+
let toPrint = "";
202+
toPrint = await addString(toPrint, "A");
203+
toPrint = await addString(toPrint, "B");
204+
toPrint = await addString(toPrint, "C");
205+
console.log(toPrint); // Prints out " A B C"
206+
}
207+
addAll();
208+
```
209+
210+
#### Further Reading
211+
212+
https://medium.com/front-end-weekly/callbacks-promises-and-async-await-ad4756e01d90 - Very good explanation

0 commit comments

Comments
 (0)