Est. reading time: 5 mins
I've worked with JavaScript (JS) callbacks for quite some time now without really understanding how, or why they work the way that they do. So I'm here to hopefully help you learn a bit more about them!
For those who are unfamiliar with what a JS callback is, it's defined as 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 😱.
JavaScript is a single-threaded programming language. Meaning it's synchronous by default, and processes one operation at a time. This can vary depending on how you're using it and on which environment it (JS) is being used in, client 💻 vs server side 🗄.
Let's take a look at our first example of some browser code:
function fruitOne(){
console.log('Apples are the best! 🍏')
}
function fruitTwo(){
console.log('Bananas are the best! 🍌')
}
function fruitThree(){
console.log('Cherries are the best! 🍒')
}
fruitOne()
fruitTwo()
fruitThree()
// RESUlT
Apples are the best!
Bananas are the best!
Cherries are the best!
Works a bit how we'd expect, right? The console logs each result in the order that their functions were called.
But now what do we think might happen if we use the Web API Method, setTimeout() inside one of the functions here in our second example:
function fruitOne(){
console.log('Apples are the best! 🍏')
}
function fruitTwo(){
setTimeout(() => console.log('Bananas are the best! 🍌'), 3000)
}
function fruitThree(){
console.log('Cherries are the best! 🍒')
}
fruitOne()
fruitTwo()
fruitThree()
// RESULT
Apples are the best!
Cherries are the best!
Bananas are the best!
We can see the functions are being called in the same order as before, but see them return in a different order! Now, why is that 🤔?
Well, JS is a non-blocking programming language, meaning that it won't wait for previous code to finish executing before moving on to the next piece of code 🤯.
So in our most recent example, fruitOne() gets called, and returns immediately. Then we get to fruitTwo() which contains the setTimeout() web api method.
The setTimeout() method sets a timer which executes a function or specified piece of code once the timer expires, in this case it will execute after 3 seconds.
The fruitThree() method does not wait for fruitTwo() to finish executing before it gets called, it want's to run asap!
Now we're seeing some asynchronous behavior! Functions returning in a different order than which they were called.
Let's look at a third example now!
function fruitOne(){
console.log('Apples are the best! 🍏')
}
function fruitTwo(myCallback){
setTimeout(() => {
console.log('Bananas are the best! 🍌')
callback()
}, 3000)
}
function fruitThree(){
console.log('Cherries are the best! 🍒')
}
fruitOne()
fruitTwo(fruitThree)
// RESULT
Apples are the best!
Bananas are the best!
Cherries are the best!
An important distinction for our third example above is that we're no longer invoking the functions one after another. We're passing the fruitThree function as an argument to fruitTwo().
👻 Sneaky Note: Notice that when we pass fruitThree into fruitTwo as an argument, we omit the "()" we normally use for functions. The () is a signal to invoke the function, and we don't want to do that just yet! We're just passing a reference to the fruitThree function with no intention telling that code to execute yet.
So inside fruitTwo we have access to the myCallback parameter. The way this example works, is that our fruitOne function runs first, and then we call the fruitTwo function. Our third function waits for the second to finish before it gets the go-ahead!
Inside fruitTwo() there is a setTimeout that executes 3 seconds after it's invoked. Once it's called it logs the 'banana' statement, and then finally it will run the callback function we named myCallback, which is really the fruitThree function in disguise 🥸.
Notice this time we do use the () when invoking the myCallback function param our fruitTwo function has access to.
And that's a little fun with callbacks! Callbacks are great for small tasks like this, but can quickly get out of hand with multiple nested callbacks, there's a name for this, Callback Hell 👹! There are other solutions to this though!
Things like Async/Await and Promises are great tools to help manage situations like these, they're outside the scope of this post, but we can get to them one day 😉
If anybody has any tips or wants to add something I missed, please let me know!
Much love, till next time!💙
Top comments (2)
Great explanation ! Thank you, very helpful.
Thank you Jacqueline! 💙