Here is an example that show you why you have to use async/await especially in many callback functions in a single task. Assume that we have a function which multiply ‘x’ by 2 (200 ms).
output = x * 2
Here is the function with a callback parameter.
function slowDoubleCallback(x, callback) { setTimeout(() => { callback(x * 2); }, 200); }
If we would like to call it 10 times, in callback version would be like this:
// Callback Hell Version let callBackAns = 0; slowDoubleCallback(1, (ans) => { callBackAns += ans; slowDoubleCallback(2, (ans) => { callBackAns += ans; slowDoubleCallback(3, (ans) => { callBackAns += ans; slowDoubleCallback(4, (ans) => { callBackAns += ans; slowDoubleCallback(5, (ans) => { callBackAns += ans; slowDoubleCallback(6, (ans) => { callBackAns += ans; slowDoubleCallback(7, (ans) => { callBackAns += ans; slowDoubleCallback(8, (ans) => { callBackAns += ans; slowDoubleCallback(9, (ans) => { callBackAns += ans; slowDoubleCallback(10, (ans) => { callBackAns += ans; console.log("Callback: " + callBackAns); }); }); }); }); }); }); }); }); }); });
That is horrible, right? Now, make a Promise version. To do this, we need to modify the function to return Promise object:
function slowDouble(x) { return new Promise((resolve) => { setTimeout(() => { resolve(x * 2); }, 200); }); }
To call it 10 times, would be like this:
// Promise Version let promiseAns = 0; slowDouble(1).then((ans) => { promiseAns += ans; return slowDouble(2); }).then((ans) => { promiseAns += ans; return slowDouble(3); }).then((ans) => { promiseAns += ans; return slowDouble(4); }).then((ans) => { promiseAns += ans; return slowDouble(5); }).then((ans) => { promiseAns += ans; return slowDouble(6); }).then((ans) => { promiseAns += ans; return slowDouble(7); }).then((ans) => { promiseAns += ans; return slowDouble(8); }).then((ans) => { promiseAns += ans; return slowDouble(9); }).then((ans) => { promiseAns += ans; return slowDouble(10); }).then((ans) => { console.log("Promise: " + (promiseAns + ans)); });
Much better in Promise version? Now in async/await version:
// async / await Version (async () => { let ans = 0; ans += await slowDouble(1); ans += await slowDouble(2); ans += await slowDouble(3); ans += await slowDouble(4); ans += await slowDouble(5); ans += await slowDouble(6); ans += await slowDouble(7); ans += await slowDouble(8); ans += await slowDouble(9); ans += await slowDouble(10); console.log("async/await: " + ans); })();
Extremely clear, isn’t it? Not just for readability. You could add for-loop here like structured programming which is difficult in callback/promise (Edit: a redditor pointed out that you can do this with Promise) version.
// async / await Version 2 (async () => { let ans = 0; for (let i = 1; i <= 10; i++) { ans += await slowDouble(i); } console.log("async/await Version 2: " + ans); })();
Hope you could feel the benefit of async/await after read the example. Not saying callback is useless, it is still useful in a simple situation. However, it is much clear to write async/await in complicated situation.
Tested on: Node.js 8.10.0
Gist:
https://gist.github.com/louislam/a4ffc57fb9fd4596a0092d1054eabcee
Reddit Thread:
https://www.reddit.com/r/javascript/comments/85j6tu/for_beginners_i_wrote_an_article_to_help_you/