Q
Q
quex2014-07-24 03:55:08
Node.js
quex, 2014-07-24 03:55:08

Is there a better way to go from events to callbacks in NodeJS?

there is a third-party module inherited from EventEmitter, let's call it SuperModule. when a certain #start method is called, the error or started event is emitted. passing a callback to #start is not provided by the module developer. it is necessary to execute a chain of asynchronous function calls, one of the links of which is
the #start call.
you need to provide support for such a call (with the transfer of a callback):
SuperModuleInstance.start(function(err){...});
Now it is implemented as follows:

var SuperModule = require('SuperModule');

SuperModule.prototype.startcb = function(callback){
  var cb = function(err){
    this.removeListener('error', cb);
    this.removeListener('started', cb);
    callback(err); // err == null при started
  }
  this.on('started', cb);
  this.on('error', cb);
  this.start();
}

...

async.series([
  ...,
  SuperModuleInstance.startcb.bind(SuperModuleInstance),
  ...], 
finalCallback);

are there any more elegant alternatives? It's just not the first time there's a need to do something like this.
fork of the module, as well as edits in node_modules are not considered.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
K
Konstantin Kitmanov, 2014-07-24
@quex

Use an adapter . Like this:

var SuperModuleAdapter = function () {
    this.adapted = new SuperModule() 
}

SuperModuleAdapter.prototype = {
    start: function (callback) {
        var cb = function(err){
            this.adapted.removeListener('error', cb);
            this.adapted.removeListener('started', cb);
            callback(err); // err == null при started
        }
        this.adapted.on('started', cb);
        this.adapted.on('error', cb);
        this.adapted.start();
    }
}

A
Alexander Keith, 2014-07-24
@tenbits

Here are more options:

var SuperModule = require('SuperModule');
var start_ = SuperModule.prototype.start;

SuperModule.prototype.start = function(cb){
    var fn = onceDelegate(cb);
    this
        .once('started', fn)
        .once('error', fn)
        ;
    start_.call(this);
};

function onceDelegate(fn) {
    return function(){
        var x_ = fn;
        fn = null;
        x_ && x_.apply(null, arguments);
    };
}


// ИЛИ, если сделать более общим:
function callbackInjector(Ctor, method, events) {
    var orig_ = Ctor.prototype[method];
    
    Ctor.prototype[method] = function(){
        var args = Array.prototype.slice.call(arguments),
            cb = args.pop(),
            listener = onceDelegate(cb),
            imax = events.length,
            i = -1
            ;
        while(++i < imax) this.once(events[i], listener);
        return orig_.apply(this, args);
    }
};

callbackInjector(SuperModule, 'start', ['started', 'error']);

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question