Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement reusable callback functions

I am fairly new to JavaScript and I am working in node which requires a good understanding of async programming and callback design. I have found that using embedded functions is very easy to do even when your callbacks are multiple levels deep. Your embedded callbacks just end up being closures.

However, when you have several layers of callbacks where many of the callbacks are similar across execute routes, you end up rewriting a lot of callback code over and over in separate callback chains. For example, if mycb1 and mycb2 definitions below are moved outside of A, they no longer have implicit access to A's variables and thus, no longer function as closures.

Example with embedded definitions where they function as closures.

mod.A=function(){
  var mycb1=function(err){
    if (!err){
      var mycb2=function(err){
        cb(err);
      };
      mod.foo2(args,mycb2);
    }
    else{cb(err);}
  };
  mod.foo1(args,mycb1);
}

mod.foo1 = function(args,cb){
  //do some work
  cb(err);
};

mod.foo2 = function(args,cb){
  //do some work
  cb(err);
} 
//execute
mod.A();

I want to do the following but be able to change the variable scope for mycb1 and mycb2 functions so they can be used as closures from where ever they are called. For example:

var mycb2=function(err){
  ...
  cb(err);
};

var mycb1=function(err){
  if (!err){        
    mod.foo2(args,mycb2);  //but have it act like a closure to mycb1
  }
  else{cb(err);}
};

mod.A=function(){
  ...
  mod.foo1(args,mycb1);  //but have it act like a closure to A
} 

mod.foo1 = function(args,cb){
  //do some work
  cb(err);
}

mod.foo2 = function(args,cb){
  //do some work
  cb(err);
}

I know that I can implement a design that either sets variable at the mod level so they are accessible to mod level functions. However, this seems to somewhat pollute the mod scope with variable that may only be used by a few of its' methods. I also know that I could pass in variables to make them accessible to the callbacks when they are executed. However, if I understand how JS and callbacks work, I would have to pass those to fooX and then have foo pass them to the callbacks. That doesn't seem like a good plan either. Can the variable scope of a function be changed so it acts like a closure from its point of execution rather than its point of definition? If not, what is the best way to modularize your callback code so it can be reused?

like image 418
rss181919 Avatar asked Jan 16 '15 20:01

rss181919


1 Answers

In general, there is no getting around having to create another function in-line that has access to the closures. You can create the function in-line by having a simple anonymous function that passes some arguments to the parent callback as parameters while accepting the rest (i.e. a partial function), or by using Function.bind() to create the partial function itself.

For example, if you initially had:

function(...) {
    // closure vars x1, y1
    foo.bar( function(result) {
        // do something with x1 and y1
    });
}

You could extract that to:

var callback = function(x1, y1, result) {
    // do something with x1 and y1
};

function(...) {
    // closure vars x1, y1

    // option 1: make your own partial function
    foo.bar( function(result) { return callback(x1, y1, result); });
    // with ES6: foo.bar( (result) => callback(x1, y1, result); });

    // option 2: use Function.bind
    foo.bar( callback.bind(this, x1, y1); );
}
like image 61
EyasSH Avatar answered Sep 30 '22 03:09

EyasSH