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

Posted

技术标签:

【中文标题】如果尚未添加侦听器并且侦听器处理程序是匿名函数,则在 nodeJS 中添加侦听器【英文标题】:Adding listeners in nodeJS if the listener is not already added and listener handler is an anonymous function 【发布时间】:2016-12-06 15:39:49 【问题描述】:

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

获取db的对象 做一些操作 如果尚未添加相同的侦听器,则添加侦听器,例如错误、结果、排水等 [假设对于所有操作,侦听器操作都相同]

我想优化侦听器的添加,使我们尝试添加现有侦听器时不会添加新侦听器。节点文档说“不检查是否已经添加了侦听器。传递相同 eventName 和侦听器组合的多个调用将导致侦听器被添加和调用多次。

有办法解决吗? [编辑]-添加一些示例代码

 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 将包含一个 db 连接,它来自一个外部包。在语句 connection.on('error', function(err)onErr(err,connection););我正在使用匿名函数,因为我需要将一个额外的参数传递给清理方法。在清理期间,我没有得到函数的处理程序,因为我使用的是匿名函数。

【问题讨论】:

只需检查listeners currently bound to the particular event 以查看您要添加的是否存在。使用emitter.listeners(eventName) @CoolBlue:我如何检查受 util.inspect 绑定的侦听器的名称?它将输出返回为:“add 中的侦听器是 [ [Function], [Function: g] listener: [Function] , [Function], [Function] ]” 只需使用对侦听器函数的引用来检查emitter.listeners(eventName) 返回的侦听器数组。请参阅下面的答案... 不幸的是,我正在为侦听器处理程序使用匿名函数。这些事件是从 mysql 包中抛出的,它们只接受 err 作为参数。我将编辑问题以包含一些代码 您可以将onErrcleanup 函数移动到getConnection 回调的范围内。然后您可以使用(未​​包装的)onErr 作为侦听器,但将其签名更改为onErr(err) 并按词法访问connection 【参考方案1】:

只要在你hook的时候保持对监听器的引用,就可以检查它是否在emitter.listeners(eventName)返回的监听器数组中。

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

/**
 * Created by cool.blue on 8/4/2016.
 * http://***.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;DR

基本思想是为侦听器使用非匿名函数,并传递对它的引用以及与外部范围内的实用函数的连接。

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('\n\x1b[33m' + context + '\n'
        + 'before:\t' + h._eventsCount + '\x1b[0m\n' + util.inspect(h));
    h.removeListener(l.e, l);
    console.log('\n\x1b[33mafter:\t' + h._eventsCount + '\x1b[0m\n' + util.inspect(h));
    delete l.e

IIFE 只是为了模拟您在外部范围内没有引用 host (connection) 的情况。

【讨论】:

感谢您的 sn-ps,我提出了一个结合这两个方面的解决方案。抱歉延迟回复!

以上是关于如果尚未添加侦听器并且侦听器处理程序是匿名函数,则在 nodeJS 中添加侦听器的主要内容,如果未能解决你的问题,请参考以下文章

事件监听器操作

[Javascript] Promise

删除匿名事件侦听器

十三周总结

jquery,添加和删除事件处理程序[重复]

`this.some_property` 在匿名回调函数中变得未定义