Callback Functions Double Executing? Dont Forget To return

Callback Functions Double Executing?

A quick example

function doSomething(err, result, final){
 if(err){
   final(err);
 }
 final(null,result);
}

Take the above as a simple way to express how you would have your final execute twice.

It may not be immediately apparent why the callback executes twice, consider the scenario below;

var match = 3;
(function(id, callback){
  var interval = setInterval(function(){
    var random = (Math.floor(Math.random() * 5) + 1);
    if (random === id) {
      var err = new Error("process terminated");
      callback(err,{},final);
      return false;
	}
    callback(null, { some: "data", id: id }, final);
  }, 5000 );
})(match, doSomething);

Here we are matching a random number between 1 and 5 with a number stored in id which was defined by var match as 3. Our doSomething callback is also provided as a callback in argument callback.

Every 5 sec we do this with a new random number (always the interval will call callback) and for each iteration the callback function is called either with an exception or some data to be processed.

Notice the return false after we call callback, consider the random number to be a killswitch.

Note: Previously I wrote about Node.js Error Handling Patterns, that the first argument for callbacks should always be the error.

The scenario ensures the callback is not executed twice when we encounter the killswitch (match the random number) because we only want to pass an instance of Error to the callback in-line with best node.js practice, not provide the callback doSomething data to process when we match the killswitch.

When we have no match, we send some results to the callback as well as our final callback function which is expected to be executed once after each callback regardless if there was an Error (final can handle the Error).

As we saw in the begining, final executes twice in doSomething when there is an Error. Fixing the doSomething is easy, just add a return false when there is an Error, just like our scenario.

function doSomething(err, result, final){
 if(err){
   final(err);
   return false;
 }
 final(null,result);
 return result;
}

And add a return to the callback also, to return the result.

Conclusion

A common mistake made by all early node developers is forgetting to return after a callback. While sometimes this has no implications, there are many times where you will run into odd issues or worse, debugging nightmares because your callback is being called twice.

Enjoyed this?

If you made it here I would love to hear what you thought of the article.

Subscribe to Christopher D. Langton

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe