Search code examples
node.jseventemitter

NodeJS eventEmitter.emit: this is not the expected scope


I want to load some of my objects in specific orders, like first connect to the database, then start mail service, then start load game things and at last I want to start the webserver so everything is loaded before going online.

I made a chain like this:

db.on('ready', mail.init);
mail.on('ready', game.init);
game.on('ready', ws.start);
db.init();

Db module looks like this:

var config = namespace('config'),
    mongoose = require('mongoose'),
    events = require('events'),
    util = require('util');


function DataBase() {
  events.EventEmitter.call(this);

  this.init = function() {
    self = this;

    mongoose.connect('mongodb://'+config.db.host+':'+config.db.port+'/'+config.db.database);
    mongoose.connection.on('error', console.error.bind(console, '[Database] ERROR:'));
    mongoose.connection.once('open', function() {
      console.log('[database] ready')
      self.emit('ready', {caller: 'database'});
    });
  }
}

util.inherits(DataBase, events.EventEmitter);

module.exports = exports = new DataBase();

The Mail class looks like this:

var Mail = function() {
  events.call(this);

  this.send = function(mailinfo) {
    var mailData = {
      from: config.mail.from,
      to: to,
      subject: subject,
      text: templates[template]
    };



    transporter.sendMail(mailData, function(err, info) {
      if (err)
        console.log(err);
      else
        console.log('Message sent: ' + info.response);
    });
  }

  this.init = function(data) {
    console.log(this.constructor);
    this.emit('ready', {caller: 'mail'});
  }
}

util.inherits(Mail, events);

When I start the script, database executes properly, ready is emitted, init function of mail is called, but then it come to a loop when this.emit is called.

As you can see, I already tryd to find out why it's endless looping around mail. the

console.log(this.constructor);

says it's DataBase, so instead of emitting in the Mail scope, it still emitts in the DataBase scope because this = DataBase.

Why is "this" in the Mail "class" Database and not Mail? How can I fix my Problem? Did I create the class wrong?


Solution

  • When you do db.on('ready', mail.init) you are passing the mail init function as the callback but without its context. You need to specify a context, for example with .bind:

    db.on('ready', mail.init.bind(mail))