How can I corral a method which may contain it's own async calls without having write access to the file?

I have a set of files, module1.js, module2.js, module3.js, and each of these contains a return object which has property-methods that will be executed. The objects are inspected to determine the property names dynamically, and I can .toString() the methods.

The inner methods will almost certainly contain async calls, like this:

function doSomething(vars){
  var that = this,
      red = 'blue',
      up = 'down',
      one = 2;

   makeAsync(that,red,up,one,function(err,res){
      return makeDeep(res);
   }
}

How can I marshall these methods from a calling parent method to eventually return the value without actively having writeable access to the files module1.js, module2.js and module3.js. Assume those are cast in stone, and can never be edited. Anything else that's reasonable is fair game. Just please don't say "well, rewrite doSomething to pass in a CB and let the makeDeep be wrapped in the CB". Note that I'm calling this module from my own code, and note that makeAsync is whatever asynchronous methods the module-author wants to call.


IMPORTANT NOTE: I am the one writing makeDeep and I am the one including the module so I can do whatever you want in either of those two places, and makeDeep is injected into the module dynamically (I'm doing a mixin pattern) so if your solution relies on modifying makeDeep to work or something in the "parent" calling method, that is 100% reasonable and I'm all about that.

If this is the case, there's no "need" to have the return keyword before makeDeep but bonus points if the syntax does use those words (that heavily indicates to a developer that that's a code exit point, yes?)


Assume that module1.js looks like:

module.exports = function() {
    this.doSomething11 = function doSomething(vars){
      var that = this,
          red = 'blue',
          up = 'down',
          one = 2;

       makeAsync(that,red,up,one,function(err,res){
          return makeDeep(res);
       }
    }
}

module2.js

module.exports = function() {
    this.doSomething21 = function doSomething(vars){
      var that = this,
          red = 'blue',
          up = 'down',
          one = 2;

       makeAsync(that,red,up,one,function(err,res){
          return makeDeep(res);
       }
    };

    this.doSomething22 = function doSomething(vars){
      var that = this,
          red = 'blue',
          up = 'down',
          one = 2;

       makeAsync(that,red,up,one,function(err,res){
          return makeDeep(res);
       }
    };
}

module3.js

module.exports = function() {
    this.doSomething31 = function doSomething(vars){
      var that = this,
          red = 'blue',
          up = 'down',
          one = 2;

       makeAsync(that,red,up,one,function(err,res){
          return makeDeep(res);
       }
    };

    this.doSomething32 = function doSomething(vars){
      var that = this,
          red = 'blue',
          up = 'down',
          one = 2;

       makeAsync(that,red,up,one,function(err,res){
          return makeDeep(res);
       }
    };

    this.doSomething33 = function doSomething(vars){
      var that = this,
          red = 'blue',
          up = 'down',
          one = 2;

       makeAsync(that,red,up,one,function(err,res){
          return makeDeep(res);
       }
    }
}

Yes, the examples are contrived, because I'm more focused on concept than I am on actual specifics. They could be triply nested callbacks, or could use some sort of internal callbacks. Mostly I just want to know if there's a way to make this happen.

If not, how can I make it work for the users if I provide them a specific library and have them return into the library?

My goal is to end up replicating something similar to the ASP.NET style ActionResult, and I'm open to the idea of using Q, fibers or promises, but I'm missing something around the invocation to get it back when an async callback is used.

I'll have a go at your problem which only requires the required module to call return that.makeDeep() instead of just return makeDeep(). I know you did not want to change the called code, but hey, you can always use burrito and change those lines dynamically (no write access needed).

calling code

var Controller = require('./module1');
assert(typeof Controller == 'function');

httpServer.on('request', function(req, res) {
    // I assume this is something you would do
    var vars = processReqParameters(req);
    var action = vars.action;
    var controller = new Controller();

    if(typeof controller[action] === 'function') {
        // now I assume that makeDeep will at one point
        // call res.end();
        var makeDeep = createMakeDeep(req, res, vars) // or other parameters

        // this is how we inject makeDeep in the controller
        var controllerInstance = Object.create(controller, {makeDeep: makeDeep});
        return controllerInstance[action](vars);
    }
    else {
        res.writeHead(404, 'Controller Not Found');
        res.end('Too bad\n');
    }
})

called code

module.exports = function() {
    this.myAction = function(vars)  {
        var that = this,
            red = 'blue',
            up = 'down',
            one = 2;

        makeAsync(that, red, up, one, function(err, res) {
            return that.makeDeep(res);
        })
    }
}