如果尚未添加侦听器,并且侦听器处理程序是匿名函数,则在nodeJS中添加侦听器



有没有办法检查node.js中是否已经存在对象的侦听器?我想实现以下场景:

  • 获取数据库的对象
  • 做一些操作
  • 如果尚未添加相同的侦听器,则添加侦听器,例如error、result、drain等[假设所有操作的侦听器操作都相同]

我想优化监听器的添加,这样,如果我们尝试添加现有监听器,就不会添加新的监听器。节点文档中说:"不检查是否已经添加了侦听器。多次调用传递相同的eventName和侦听器组合将导致侦听器被添加和调用多次。"

有办法绕过它吗
[EDIT]-添加一些示例代码

 connpool.getConnection(function(err, connection) {
      var querystr = "Some valid SQL query";
      connection.execute(querystr, data, function(err, rows) {
        if (err) {
          console.error(err);
        }
        connection.on('error', function(err){onErr(err,connection);});
        do some stuff
        cleanup(connection);
    });
    })  
   var onErr = function(err, connection) {
      console.error({"Error message"});
      connection.release();
      cleanup(connection);
   };
   var cleanup = function(conn) {
    conn.removeListener('error',onErr);
   };

连接将包含一个数据库连接,它来自一个外部包。在语句connection.on('error',function(err){onErr(err,connection);});我使用了一个匿名函数,因为我需要向cleanup方法传递一个额外的参数。在清理过程中,我没有得到函数的处理程序,因为我使用的是匿名函数。

只要在挂接侦听器时保留对它的引用,就可以检查它是否在emitter.listeners(eventName)返回的侦听器数组中。

粗略的例子(我相信它可能更有效)

/**
 * Created by cool.blue on 8/4/2016.
 * http://stackoverflow.com/q/38700859/2670182
 */
const EE = require('events');
const util = require('util');
var host = new EE();
// set up a emitter with n events
const n = 10;
const events = Array.apply(null, Array(n)).map((x, i) => 'event_' + i);
events.forEach(function(e){
    host.on(e, function g() {console.log(e)})
});
console.log(util.inspect(host));
// get a reference to one of the listener functions
const target = 'event_3';
var probe = host.listeners(target)[0];
// add a method to only add unique listeners
host.onUnique = function (type, listener){
    var slot = this.listeners(type).find(function(l) {
        return l === listener
    });
    if(slot)
        return this;
    console.log('adding');
    return this.on(type, listener)
};
// try to add the same listener again
var count0 = host.listenerCount(target);
var count1 = host.onUnique(target, probe).listenerCount(target);
console.log('added ' + (count1 - count0) + ' listeners');   // added 0 listeners
console.log(util.inspect(host));
// try to add a new listener
count0 = host.listenerCount(target);
count1 = host.onUnique(target, function h(){ console.log('different cb')}).listenerCount(target);
console.log('added ' + (count1 - count0) + ' listeners');   // added 1 listeners
console.log(util.inspect(host));

针对更新的问题

你可以做这样的事。。。

TL;博士

其基本思想是为侦听器使用一个非匿名函数,并传递对它的引用以及到外部范围中实用程序函数的连接。

const EE = require('events');
const util = require('util');
(function manage(host){
    host.name = 'host';
    host.release = function(){
        console.log('released!')
    };
    function l(err) {
        onErr(err, host, l)
    }
    l.e = 'error';
    host.on('error', l);
    if(Math.random() > 0.5)
        host.emit('error', new Error('oops!'));
    if(l.e)
        cleanUp(host, l, 'manage');
})(new EE());
function onErr(e, h, l) {
    console.error(`n${h.name}: ${e.message}`);
    h.release();
    cleanUp(h, l, 'onError')
}
function cleanUp(h, l, context){
    console.log('nx1b[33m' + context + 'n'
        + 'before:t' + h._eventsCount + 'x1b[0mn' + util.inspect(h));
    h.removeListener(l.e, l);
    console.log('nx1b[33mafter:t' + h._eventsCount + 'x1b[0mn' + util.inspect(h));
    delete l.e
}

IIFE只是模拟在外部范围中没有引用hostconnection)的情况。

最新更新