Javascript : Callbacks, Promises, and Async/Await

Vipin Cheriyanveetil
tinywave
Published in
7 min readOct 8, 2021
Javascript : Callbacks, Promises, and Async/Await

The Real version of this blog post is at my personal space https://buddyclaps.com/javascript-callbacks-promises-async-await/

Hello programmers,

This article is for all those who wants to understand the below topics. I love Javascripting and I am into Javascripts from more than 3 years now.

  • Callbacks
  • Promises
  • Async and Await

This article should help us in understanding few javascript concepts like

  • What is Synchronous Operation ?
  • What is Asynchronous Operation ?
  • What is Callback and an example ?
  • What is Promises and an example ?
  • How Async and Await works in javascript with example?

What is Synchronous Operation ?

This is the most efficient way of getting a task done. Synchronous focuses on getting tasks done one by one or one after another or getting tasks done sequentially. I like this approach as it makes code more easy to understand and debug. This also means that the other tasks waits until their turn arrives.

By default Javascript is synchronous or single threaded. it is designed to do one task at a time.

Let’s look at a simple example. Look at the below code

console.log("I am First")
console.log("I am Second")
console.log("I am Third")

The output on console would be

"I am First"
"I am Second"
"I am Third"

What is Asynchronous Operation ?

Asynchronous is exactly the opposite of synchronous operation. Which means the tasks can run independent to each other and no task has to wait for others. This approach is great when you want to make your code more efficient and fast. Imagine if you can do multiple tasks at a time and finish it all. Wow ! how great that would be. Not sure if humans can do this effectively but machines and javascript can.

Let’s look at a simple example. Look at the below code

console.log("David Reached School")
setTimeout(() => {
console.log('Liz reached school')
}, 3000)
setTimeout(() => {
console.log('Bill Reached school')
}, 2000)
console.log("Mike Reached School")

The output on console would be

"David Reached School"
"Mike Reached School"
"Bill Reached school"
"Liz reached school"

If you look at the above output, the output is not in the order in which they are programmed but instead its in the order in which it got completed.

Callbacks : what’s that ?

In JavaScript, a callback is a function passed into another function as an argument to be executed later. When you pass a callback function into another function, you just pass the reference of the function i.e., the function name without the parentheses () .

OR

A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action.

An Example

function announce() {
console.log('Yea!, the hot water is ready !')
}
function boil_water(shoutIt) {
console.log('Water is boiling')
setTimeout(() => {
shoutIt()
}, 3000)
}
boil_water(announce)

If you look at the code “boil_water(announce)“, you see that method “announce” is passed as a reference to “boil_water” method and “boil_water” is invoking the reference method when needed. So this becomes a simple example for how to use a callback. Hope its easier to understand.

Callback Hell: OMG, now what is that ?

I thought callbacks were great and interesting. But, wait ! what’s this now.

let’s look at an example straight away.

setTimeout(() => {
console.log('Sunday')
setTimeout(() => {
console.log('Monday')
setTimeout(() => {
console.log('Tuesday')
setTimeout(() => {
console.log('Wednesday')
setTimeout(() => {
console.log('Thursday')
setTimeout(() => {
console.log('Friday')
setTimeout(() => {
console.log('Saturday')
setTimeout(() => {
console.log('Wow! week is over')
}, 2000)
}, 2000)
}, 2000)
}, 2000)
}, 2000)
}, 2000)
}, 2000)
}, 2000)

Output:

"Sunday" (After 2 seconds)
"Monday" (After 2 seconds)
"Tuesday" (After 2 seconds)
"Wednesday" (After 2 seconds)
"Thursday" (After 2 seconds)
"Friday" (After 2 seconds)
"Saturday" (After 2 seconds)
"Wow! week is over" (After 2 seconds)

The code above is a perfect example of “Callback Hell“. Below are some problem of “Callback Hell“.

  • It’s hard to read or poor readability.
  • Hard to understand the code.
  • It’s even harder to debug
  • Difficult to add error handling.

Callback Hell” is also known as “Pyramid of doom” or “Christmas tree of hell“. No matter whatever different names you give , the problems remains the same.

Don’t worry. “Promises” can help us. I promise you that. But don’t take my words.

Wow ! Promises

Promises” as designed to help us from “callback hell” and more importantly it helps us to better handle our code and tasks. That’s so relieving to hear.

Now, let’s understand “Promises” better. Promises has few states to go through. Below are more info about them

  • Pending : This is just an initial state. Example : Just consider a customer is visiting your shop and going through your menu before making an order.
  • Resolved : It’s like customer made an order and they got the order delivered to their hand and they are very happy.
  • Rejected : It’s like customer ordered something which is not available and he left the shop without getting anything.

Wow, how easy is this to understand. See i promised you that it will be easy to understand. I keep my promises !!!! . Have a look at the same thing like a flowchart or an image below.

Everything is good so far. Lets write a simple promise example.

var is_printer_on = true
let take_print = (printText) => {
return new Promise((resolve, reject) => {
if (is_printer_on) {
setTimeout(() => {
resolve('Printed :' + printText)
}, 2000)
} else {
reject('Printer is off')
}
})
}

So, this is a very simple method that uses promises to take a print of the given printText. Let’s see how to use this method. This method gives different output based on if the printer is on or off.

ie if “var is_printer_on = true” then printer is ON

else if “var is_printer_on = false“) then printer is OFF

Invoke with Printer = ON

var is_printer_on = true
let take_print = (printText) => {
return new Promise((resolve, reject) => {
if (is_printer_on) {
setTimeout(() => {
resolve('Printed :' + printText)
}, 2000)
} else {
reject('Printer is off')
}
})
}
take_print('hello world')
.then((res) => {
console.log('Success : ', res)
})
.catch((err) => {
console.log('oops!,', err)
})
.finally(() => {
console.log('Have a good day')
})

Output

After 2 seconds
"Success : Printed :hello world"
"Have a good day"

Now lets turn OFF the printer

Invoke with Printer = OFF

var is_printer_on = false
let take_print = (printText) => {
return new Promise((resolve, reject) => {
if (is_printer_on) {
setTimeout(() => {
resolve('Printed :' + printText)
}, 2000)
} else {
reject('Printer is off')
}
})
}
take_print('hello world')
.then((res) => {
console.log('Success : ', res)
})
.catch((err) => {
console.log('oops!,', err)
})
.finally(() => {
console.log('Have a good day')
})

Output

"oops!, Printer is off"
"Have a good day"

Great, so you just saw a promise that can take the “Resolved” state when Printer was ON and it took a “Rejected” state when Printer was OFF. And irrespective of the state we got the finally block also executed. So I hope “promises” are now making sense.

Async / await

Promises” were introduced in javascript to handle asynchronous activity or operation easily. The Async/Await is a syntactical sugar added to easily work with promises. The intention is that async/await will help in making the code look synchronous while performing asynchronous activity.

So let’s write the same “take_print” promise using the async / await keywords. We might need to make slight changes to the “take_print” method and the way it needs to be invoked.

Invoke with Printer = ON

var is_printer_on = true
let take_print = async (printText) => {
return new Promise((resolve, reject) => {
if (is_printer_on) {
setTimeout(() => {
resolve('Printed :' + printText)
}, 2000)
} else {
reject('Printer is off')
}
})
}
async function testcode() {
try {
let res = await take_print('hello world')
console.log('Success : ', res)
} catch (err) {
console.log('oops!,', err)
} finally {
console.log('Have a good day')
}
}
testcode()

Output

After 2 seconds
"Success : Printed :hello world"
"Have a good day"

Invoke with Printer = OFF

var is_printer_on = false
let take_print = async (printText) => {
return new Promise((resolve, reject) => {
if (is_printer_on) {
setTimeout(() => {
resolve('Printed :' + printText)
}, 2000)
} else {
reject('Printer is off')
}
})
}
async function testcode() {
try {
let res = await take_print('hello world')
console.log('Success : ', res)
} catch (err) {
console.log('oops!,', err)
} finally {
console.log('Have a good day')
}
}
testcode()

Output

"oops!, Printer is off"
"Have a good day"

Conclusion

Thanks for reading this article with patience. I hope my article was useful and made sense. Let me know your comments and thoughts through the comment box below.

Credits

Here I found much elaborated and in detail discussion of the same topic . I got inspired by that article and I felt I should also write something similar in my own words and examples and that’s what led to this post.

Thanks for reading !! Have a great day !

You can buy me a coffee , if you like at https://www.buymeacoffee.com/vipinc007

--

--