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/