javascript - Inject functionality into other Node.js module -


i have node.js application (using sequelize orm) try separate different modules can reused. means need remove dependencies between them, i'm struggling @ 1 point:

there's module called "account", should have (almost) 0 dependencies on other modules. provides basic account functionality.

then there other modules, have dependency on account module (which ok).

at moment, account module has dependency on other modules, i'd resolve. now, when account gets created, other modules must create objects in database. should happen in same transaction , without account module knowing other modules.

currently, looks following:

accountcontroller.prototype.createaccount = function (data) {    // validation checks etc. omited     return db.sequelize.transaction(function (t) {       return q.promise(function (resolve, reject, notify) {          _createhash(pw, 10)             .then(function (hash) {                data.passwordhash = hash;                 return _createaccount(data, t);             })             .then(function (account) {                // create user                return [account, _createuser(account, t)];             })             .spread(function (account, user) {                // create object                return [account, user, _createxxx(account, t)]             })             .spread(function(account, user, xxx) {                 // create 1 more object                return [account, user, xxx, _createyyy(account, t)];             })             .spread(function (account, user, xxx, yyy) {                resolve([account, user, xxx, yyy]);             })             .catch(reject);       });     }); }; 

now, want create account object within module, , let other modules create objects independent, in same transaction.

first thought let accountcontroller emit "createaccount" event within promise chain, hand on transaction object , let modules register listeners. noticed eventemitter works asynchronously.

what's best practice in node.js this?

ok let me answer question myself:

  • despite read different, realized eventemitter not asynchronously
  • so using events task works
  • but encountered problem, event listeners asynchronously, due database calls. therefore, needed way wait until event listeners have "really" finished.
  • i introduced promisedemit() function subclass of eventemitter, allows listener return promise , returns promise itself, finish when listener promises finished.

here's code came with:

'use strict';  var eventemitter = require('events'); var util = require('util'); var q = require('q');  function promisedeventemitter() { }  util.inherits(promisedeventemitter, eventemitter);  promisedeventemitter.prototype.promisedemit = function promisedemit(type) {    var er, handler, len, args, i, listeners;    var promises = [];     if (!this._events)       this._events = {};     // if there no 'error' event listener throw.    if (type === 'error' && !this._events.error) {       er = arguments[1];       if (this.domain) {          if (!er)             er = new error('uncaught, unspecified "error" event.');          er.domainemitter = this;          er.domain = this.domain;          er.domainthrown = false;          this.domain.emit('error', er);       } else if (er instanceof error) {          throw er; // unhandled 'error' event       } else {          throw error('uncaught, unspecified "error" event.');       }       return q.all(promises);    }     handler = this._events[type];     if (util.isundefined(handler))       return q.all(promises);     if (this.domain && !== process)       this.domain.enter();     var promise;    if (util.isfunction(handler)) {       switch (arguments.length) {          // fast cases          case 1:             promise = handler.call(this);             break;          case 2:             promise = handler.call(this, arguments[1]);             break;          case 3:             promise = handler.call(this, arguments[1], arguments[2]);             break;          // slower          default:             len = arguments.length;             args = new array(len - 1);             (i = 1; < len; i++)                args[i - 1] = arguments[i];             promise = handler.apply(this, args);       }       promises.push(promise);    } else if (util.isobject(handler)) {       len = arguments.length;       args = new array(len - 1);       (i = 1; < len; i++)          args[i - 1] = arguments[i];        listeners = handler.slice();       len = listeners.length;       (i = 0; < len; i++) {          promise = listeners[i].apply(this, args);          promises.push(promise);       }    }     if (this.domain && !== process)       this.domain.exit();     return q.all(promises); };   module.exports = promisedeventemitter; 

this original .emit code, added promise handling it. can use same way original eventemitter, , call

xxxcontroller     .promisedemit("eventname", arg1, arg2, argn)]     .then(function(){         //...     }); 

Comments

Popular posts from this blog

javascript - Slick Slider width recalculation -

jsf - PrimeFaces Datatable - What is f:facet actually doing? -

angular2 services - Angular 2 RC 4 Http post not firing -