0

In our applications, we have a data adapter module whose sole purpose is to access data in some way. These adapters are event emitters, which emit an event when a query has completed, and sends back the data in common err, data format that callbacks expect.

Let's get to some code to provide some information about the issue I'm trying to solve.

var
_ = require("underscore"),
Rosters = require("../adapters").mlb.Rosters,
dbConfig = require("../config/db"),
rosters = Rosters( dbConfig );

exports.team = function( req, res, next ) {

  var bindHelperEvents = _.once(function() {

    rosters.on("team", function(err, roster) {
      if (!err) {
        res.send( roster );
        return;
      }
      next(err);
    });

  });

  bindHelperEvents();
  rosterHelper.team( req.params );

};

You can see in the code above we're binding an event handler only once (to avoid stacking event handlers), but it happens when someone makes a request. This - in my opinion - is not a very good way of doing this.

Here's an alternate way of doing this.

var
Rosters = require("../adapters").mlb.Rosters,
dbConfig = require("../config/db"),
rosters = Rosters( dbConfig );

rosters.on("team", function(err, data, req, res, next) {
  if (!err) {
    res.send( roster );
    return;
  }
  next(err);
});

// Explicitly written for clarity
exports.team = function(req, res, next) {
  rosters.team(req, res, next);
}

You can see now, that the event handler is bound when the server starts, rather than during the request response cycle, which is what I'm looking for.

The debate I'm having deals with passing req, res, next into the adapter's function call. Ideally we'd like the adapter's interface to accept either an object of parameters, or a list of parameters rosters.teams(req.params) || rosters.teams(req.params.id, req.params.limit).

Is there a way to bind the event handler outside the req/res cycle and still have access to res, next in the scope of the callback, without changing the adapter's function call?

e.g.

var
Rosters = require("../adapters").mlb.Rosters,
dbConfig = require("../config/db"),
rosters = Rosters( dbConfig );

// How do I call res.send or next?
rosters.on("team", function(err, data) {
  if (!err) {
    res.send( roster );
    return;
  }
  next(err);
});

// Explicitly written for clarity
exports.team = function(req, res, next) {
  rosters.team(req.params);
}

EDIT (Added current code for Rosters):

var
HelperBase = require("../HelperBase"),
util = require("util");

util.inherits( Helper, HelperBase );
module.exports = Helper;

function Helper( options ) {
  if ( !( this instanceof Helper ) ) {
    return new Helper( options );
  }
  HelperBase.call( this, options );
};

Helper.prototype.team = function( params ) {
  var
  criteria = {
    id: params.id,
    ...
  };

  this.db.collection("rosters").find( {unixstamp:-1} ).sort( sortCrit ).limit(1).toArray(function( err, rosters ) {
    this.emit( "team", err, rosters[0] || {} );
    return;
  }.bind( this ) );
};
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
hellopat
  • 1,799
  • 2
  • 14
  • 14
  • Can you provide the code for Rosters? – cybersam Apr 23 '14 at 19:32
  • A quick observation: you have some logic errors in some snippets. "if (!err) {next(err);}" should be something like "if (err) {next(err); return;}" I have other things (like my actual work) to attend to, but I'll take a look at your issue when I have more time. – cybersam Apr 23 '14 at 21:31
  • Yeah. I was actually adapting the code a bit for this example and forgot the return statement. I didn't actually write the original code, I'm just trying to figure out how to make it better. – hellopat Apr 24 '14 at 13:15
  • You also need to change `(!err)` to `(err)`. – cybersam Apr 24 '14 at 18:13
  • not answering directly but using events for this purpose is an overkill plus returning errors is a bit anti-pattern. When you use events you get an automatic "error" event that is used to signal an error happened. Most design patterns for your data object use callbacks. simply return the callback win side your data access function when data is available. The only viable event use i see is returning data in chunks and emitting for each chunk, however, rare. – Biba Apr 24 '14 at 20:35

0 Answers0