nodeJs callbacks simple example nodeJs callbacks simple example javascript javascript

nodeJs callbacks simple example


var myCallback = function(data) {  console.log('got data: '+data);};var usingItNow = function(callback) {  callback('get it?');};

Now open node or browser console and paste the above definitions.

Finally use it with this next line:

usingItNow(myCallback);

With Respect to the Node-Style Error Conventions

Costa asked what this would look like if we were to honor the node error callback conventions.

In this convention, the callback should expect to receive at least one argument, the first argument, as an error. Optionally we will have one or more additional arguments, depending on the context. In this case, the context is our above example.

Here I rewrite our example in this convention.

var myCallback = function(err, data) {  if (err) throw err; // Check for the error and throw if it exists.  console.log('got data: '+data); // Otherwise proceed as usual.};var usingItNow = function(callback) {  callback(null, 'get it?'); // I dont want to throw an error, so I pass null for the error argument};

If we want to simulate an error case, we can define usingItNow like this

var usingItNow = function(callback) {  var myError = new Error('My custom error!');  callback(myError, 'get it?'); // I send my error as the first argument.};

The final usage is exactly the same as in above:

usingItNow(myCallback);

The only difference in behavior would be contingent on which version of usingItNow you've defined: the one that feeds a "truthy value" (an Error object) to the callback for the first argument, or the one that feeds it null for the error argument.


A callback function is simply a function you pass into another function so that function can call it at a later time. This is commonly seen in asynchronous APIs; the API call returns immediately because it is asynchronous, so you pass a function into it that the API can call when it's done performing its asynchronous task.

The simplest example I can think of in JavaScript is the setTimeout() function. It's a global function that accepts two arguments. The first argument is the callback function and the second argument is a delay in milliseconds. The function is designed to wait the appropriate amount of time, then invoke your callback function.

setTimeout(function () {  console.log("10 seconds later...");}, 10000);

You may have seen the above code before but just didn't realize the function you were passing in 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 all over the place in Node because Node is built from the ground up to be asynchronous in everything that it does. Even when talking to the file system. That's why a ton of the internal Node APIs accept callback functions as arguments rather than returning data you can assign to a variable. Instead it will invoke your callback function, passing the data you wanted as an argument. For example, you could use Node's fs library to read a file. The fs module exposes two unique API functions: readFile and readFileSync.

The readFile function is asynchronous while readFileSync is obviously not. You can see that they intend you to use the async calls whenever possible since they called them readFile and readFileSync instead of readFile and readFileAsync. Here is an example of using both functions.

Synchronous:

var data = fs.readFileSync('test.txt');console.log(data);

The code above blocks thread execution until all the contents of test.txt are read into memory and stored in the variable data. In node this is typically considered bad practice. There are times though when it's useful, such as when writing a quick little script to do something simple but tedious and you don't care much about saving every nanosecond of time that you can.

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 accepts two arguments err and data. One problem with asynchronous functions is that it becomes more difficult to trap errors so a lot of callback-style APIs pass errors as the first argument to the callback function. It is best practice to check if err has a value before you do anything else. If so, stop execution of the callback and log the error.

Synchronous calls have an advantage when there are thrown exceptions because you can simply catch them with a try/catch block.

try {  var data = fs.readFileSync('test.txt');  console.log(data);} catch (err) {  console.error(err);}

In asynchronous functions it doesn't work that way. The API call returns immediately so there is nothing to catch with the try/catch. Proper asynchronous APIs that use callbacks will always catch their own errors and then pass those errors into the callback where you can handle it as you see fit.

In addition to callbacks though, there is another popular style of API that is commonly used called the promise. If you'd like to read about them then you can read the entire blog post I wrote based on this answer here.


Here is an example of copying text file with fs.readFile and fs.writeFile:

var fs = require('fs');var copyFile = function(source, destination, next) {  // we should read source file first  fs.readFile(source, function(err, data) {    if (err) return next(err); // error occurred    // now we can write data to destination file    fs.writeFile(destination, data, next);  });};

And that's an example of using copyFile function:

copyFile('foo.txt', 'bar.txt', function(err) {  if (err) {    // either fs.readFile or fs.writeFile returned an error    console.log(err.stack || err);  } else {    console.log('Success!');  }});

Common node.js pattern suggests that the first argument of the callback function is an error. You should use this pattern because all control flow modules rely on it:

next(new Error('I cannot do it!')); // errornext(null, results); // no error occurred, return result