0

我在 node-mongodb-native 和 EventEmitter 之间遇到了一个奇怪的问题。

我已将问题简化为以下代码:

var mongodb = require( 'mongodb' ),
    Server = mongodb.Server,
    Db = mongodb.Db,
    events = require( 'events' ).EventEmitter.prototype;

// Create a mongo client object
var client = new Db( 'tartempion',
    new Server(
        '127.0.0.1',
        27017
    )
);

// Open the connection
client.open( function( err, db ) {
    if ( err ) throw err;
    database = db;
    console.log( 'Database driver loaded.' );
    events.emit( 'hi' );
});

// If I comment this out, I don't get the error anymore
// and the "Database driver loaded." log is displayed.
events.on( 'hi', function() {
    console.log( 'hey man' );
});

我收到了这个错误:

net.js:140
    // Uncomment the following lines after libuv backend is stable and API
      ^
RangeError: Maximum call stack size exceeded

我认为这可能与回调中的事件有关,但这段代码有效:

events.on( 'hi', function() {
    console.log( 'hey man' );
});

f( function() {
    events.emit( 'hi' );
});

function f( callback ) {
    callback();
}

所以...我没有看到问题出在哪里。

仅供参考,我在 node-mongodb-native issue queue上交叉发布了这个。

4

2 回答 2

3

如果你说:

events = require( 'events' ).EventEmitter.prototype;
event.on('foo');

你是在自找麻烦,因为每个事件对象都会得到这个绑定(因为你正在将它写入所有事件的基本原型)......

实例化一个新对象来绑定你的事件要好得多(正如乔纳森所说)......

sharedEventEmitter.js

var events = require('events');
var eventEmitter = new events.EventEmitter();
module.exports = eventEmitter;

现在从你的项目的其余部分 - 你可以把它当作一个单例 - 一个对象会向任何正在监听的东西发出事件 - 每次你需要('sharedEventEmitter')时,你都会得到相同的实例(它是一个单例):

一个.js

var sharedEvents = require('./sharedEventEmitter');
sharedEvents.on('foo', function(st){
  console.log(st);
})

b.js

var sharedEvents = require('./sharedEventEmitter');
sharedEvents.emit('hello from another file');
于 2012-08-16T19:24:57.867 回答
2

您必须定义events为一个实例,EventEmitter而不仅仅是对EventEmitter.prototype对象的引用:

var ...,
    EventEmitter = require('events').EventEmitter,
    events = new EventEmitter;

或作为继承自的对象EventEmitter.prototype

var ...,
    events = Object.create(require('events').EventEmitter.prototype);

EventEmitter.prototype每次运行只能获得一个node.exe(因为结果require('events')被缓存),因此将其用作实例可能会修改整个核心 Node API 和 .3rd 方模块(如mongodb.


正如Brandon 建议的那样,如果您需要在 2 个模块中访问实例,请在第 3 个模块中定义它:

// emitter.js
var EventEmitter = require('events').EventEmitter;
module.exports = new EventEmitter;
var ...,
    events = require('./emitter');
于 2012-08-16T18:39:04.733 回答