A callback function is just a function that you pass to another function so that the function can call it later. This is usually observed in the asynchronous API ; the API call returns immediately because it is asynchronous, so you pass it a function that the API can call when it completes its asynchronous task.
The simplest example that I can think of in JavaScript is the setTimeout() function. This is a global function that takes two arguments. The first argument is a callback function, and the second argument is the delay in milliseconds. The function is designed to wait for the appropriate amount of time, and then calls the callback function.
setTimeout(function () { console.log("10 seconds later..."); }, 10000);
You may have already seen the above code, but just did not understand that the function you were passing through was called a callback function. We could rewrite the code above to make it more obvious.
var callback = function () { console.log("10 seconds later..."); }; setTimeout(callback, 10000);
Callbacks are used throughout Node because Node is built from the ground up to be asynchronous in everything it does. Even when talking to the file system. Therefore, a ton of internal Node APIs takes callback functions as arguments, rather than returning data that you can assign to a variable. Instead, it will call your callback function, passing the data you need as an argument. For example, you can use the Node fs library to read a file. The fs module provides two unique API functions: readFile and readFileSync .
The readFile function is asynchronous, and readFileSync clearly not. You can see that they intend to use asynchronous calls whenever possible, as they called them readFile and readFileSync instead of readFile and readFileAsync . The following is an example of using both functions.
Synchronous:
var data = fs.readFileSync('test.txt'); console.log(data);
The code above blocks the execution of the stream until all the contents of test.txt are read in memory and stored in the variable data . In Node, this is usually considered bad practice. Sometimes itβs useful, for example, when writing a quick small script to do something simple but tedious, and you do not care that you can save every nanosecond of time.
Asynchronous (with callback):
var callback = function (err, data) { if (err) return console.error(err); console.log(data); }; fs.readFile('test.txt', callback);
First we create a callback function that takes two arguments err and data . One of the problems with asynchronous functions is that it becomes harder to catch errors, so many callback APIs address errors as the first argument to the callback function. Itβs best to check if err matters before doing anything else. If so, stop the callback and record the error.
Synchronous calls take precedence over exceptions, because you can just catch them with a try/catch .
try { var data = fs.readFileSync('test.txt'); console.log(data); } catch (err) { console.error(err); }
In asynchronous functions, this does not work. The API call returns immediately, so there is nothing to catch with try/catch . The correct asynchronous APIs that use callbacks will always catch their own errors, and then pass those errors to a callback, where you can handle it as you like.
In addition to callbacks, however, there is another popular API style that is commonly used called a promise. If you want to read about them, you can read the entire blog post that I wrote based on this answer here .