Introduction
The idea of callback functions was introduced due to the asynchronous nature of javascript.
What is “asynchronus” nature of javascript?
Let’s understand this thing with the help of an example.
For instance, we shall use the setTimeout function. Run the following lines in the editor mode of nodejs in your terminal.
setTimeout(() => {
console.log('Hi! Sister');
}, 5000);
console.log('Hi! Mom');
console.log('Hi! Dad');setTimeout is just a method where we can execute a piece of code after a certain time, here that time is 5 seconds&
console.log just prints any kind of message which is needed to be displayed to the user.Now…the results will look like this:
"Hi! Mom"
"Hi! Dad"
"Hi! Sister"Note that “Hi! Sister” is printed at the last although we logged it at the first.
It means that the nature of javascript doesn’t allows it to wait for a function/script/code to finish loading & engages it to start executing the next part of the code.
This is, infact, the asynchronous nature of javascript.
In a more simplified way, it is loading now but it’ll run later when loading is finished.
Callback
Let’s consider this script
function loadScript(src) {
// creates a <script> tag and appends it in the <head> of the document
// this causes the script with given src to start loading and run when complete
let script = document.createElement('script');
script.src = src;
document.head.append(script);
}
loadScript('/my/script.js');Now, if we add any code below
loadScript(…), it won’t wait for the script to load.loadScript('/my/script.js');
// the code below loadScript
// doesn't wait for the script loading to finish
Now, let’s say we have a function inside
script.js & we need to run that after the script load.loadScript('/my/script.js'); // the script has "function desiredFunction() {…}"
desiredFunction(); // no such function!
This problem is solved by callback.
function loadScript(src, callback) {
let script = document.createElement('script');
script.src = src;
script.onload = () => callback(script);
document.head.append(script);
}
loadScript('/my/script.js', function() {
// the callback runs after the script is loaded
newFunction(); // so now it works
...
});That’s the idea: the second argument is a function (usually anonymous) that runs when the action is completed.
Now let’s run this with a real script.
function loadScript(src, callback) {
let script = document.createElement('script');
script.src = src;
script.onload = () => callback(script);
document.head.append(script);
}
loadScript('https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js', () => {
alert( _ ); // _ is a function declared in the loaded script
});We’ll see an alert of
function lodash(value) {...}.That’s called a “callback-based” style of asynchronous programming. A function that does something asynchronously should provide a
callback argument where we put the function to run after it’s complete.Callback Hell/ Pyramid of Doom
Let’s take a look into this script. This mainly happens if we have to run multiple scripts and actions at the same time.
loadScript('/my/script.js', script => {
loadScript('/my/script2.js', script => {
loadScript('/my/script3.js', script => {
// ...continue after all scripts are loaded
});
});
});Now this triangular structure is affectionately called the Callback Hell or Pyramid of Doom.