Why use callback in JavaScript, what are its advantages ?
Callback functions are basically functions (either named or anonymous) that are passed into a call on another function as an argument.
The JavaScript syntax allows us to treat functions as objects so we can pass the name of a previously defined function as an argument of another function without any problem. And we can also pass the full code of an anonymous function as an argument too, e.g. in a XMLHttpRequest response handler for a form field validation process:
req.onreadystatechange = () =>
{
if (req.readyState === 4 && req.status === 200)
{
if (req.responseText !== 'Valid') // Check for invalid field value ...
{
document.getElementById(field + 'err').value = req.responseText; // ... and output detail to error field
document.getElementById(field + 'err').style.color = 'red'; // Field comment in red
document.getElementById(field + '-errchk').innerHTML = '\u00D7'; // Cross mark opposite data field
document.getElementById(field + '-errchk').style.color = 'red'; // ... in red
document.getElementById(field + '-errchk').style.fontWeight = 800; // ... and bold
}
else
{
document.getElementById(field + 'err').value = ''; // Clear error info field
document.getElementById(field + 'err').style.color = 'green'; // Field comment in green
document.getElementById(field + '-errchk').innerHTML = '\u2713'; // Check mark opposite data field
document.getElementById(field + '-errchk').style.color = 'green'; // ... in green
document.getElementById(field + '-errchk').style.fontWeight = 800; // ... and bold
}
}
}
In JavaScript the advantage of using a callback function over using a non-callback function (i.e. a function called within another function which does not include it as a parameter) lies in the callback function's range of accessible data, its scope.
Non-callback functions have access to just their own internal scope plus their own global scope plus the parameter values input to them. Beyond this they do not have any unilateral access to the scope of any code block using them. So if we want to have a non-callback function "see" certain vars/lets/consts/functions/collections within the code that calls it, we need to move the declarations of these within the scope of the non-callback function. This is always a bit cumbersome and sometimes very tricky. Otherwise we may need to redefine the non-callback function so that otherwise non-shareable data from the calling code's scope is passed as parameters to it. This of course changes the declaration of the non-callback function and impacts any other code block that uses it.
Callback functions have access to both their own scope plus the scope of the code that calls them plus the global scope of the calling code.
So callback functions are handier to manage codewise, especially in larger JS applications where data is passed across several module boundaries during execution of a task.
Callback functions existed in JavaScript from almost the beginning.
At the front end of web applications, you'll see them used in things like event listeners, for example if we want to remove the mouse's on-hover text displayed when we hover away from the "Next Month" arrow of a web page calendar :
const mouseOut = (e) =>
{
if (document.getElementById("right-info").innerHTML != "")
{
document.getElementById("right-info").innerHTML = "";
}
};
nextM.addEventListener('mouseout', mouseOut, false);
At the back end of web applications, callbacks were used for asynchronous data transfer between browser and server. They were also used as the original means of ensuring back-end JS scripts that included asynchronous functions (e.g. database queries, network calls, file-system actions, data loading from external devices, etc) would execute in the desired order. Basically, by including a callback function that does the operation needing to be done immediately after the async process as a parameter to the async function, we could ensure its correct sequencing w.r.t. the async process. The scoping privileges of a callback function helped the coding a bit too.
Nowadays use of callback functions at the back end is seldom used as modern JavaScript includes a Promise object that encapsulates handling of asynchronous processes in a clearer and more scalable way.
But it's still good to know what they are and where they can be effectively used.