How to properly remove event listeners in node js eventemitter
Asked Answered
S

2

44

I have a set up with a GET and a POST route, the idea being that POSTing to the route triggers an event, and the GET route is a server-sent eventstream which fires each time the POSTed event is triggered... however, i think i've done something wrong as event listeners seem to get added routinely despite only having one event stream subscriber... what am i doing wrong?

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

app.post('/api/:boardname/remoterefresh', function(req, res){
    var boardname = req.param('boardname'),
    data = new Date().getTime();
    rr.emit("refresh-"+boardname, data)
    res.json({data: data})
});

app.get('/api/:boardname/remoterefresh', function(req, res){
    var boardname = req.param('boardname')

    rr.on("refresh-"+boardname, function(data){
        setTimeout(function(){
            res.write('data: '+data+'\n\n');
        }, 1000)
    });

    req.socket.setTimeout(Infinity);

    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    });

    res.write('\n');

    req.on('close', function(){
        console.log('closed')
        rr.removeListener("refresh-"+boardname, function(){
            //
        })
    })

})
Selfcontrol answered 27/5, 2014 at 15:56 Comment(2)
possible duplicate of Unbinding events in Node.jsSmyth
Could this cause a race condition and leak data across requests?Corelative
S
61

You should name the function you attach as event handler. Then on removing it, you just pass the function by name:

app.get('/api/:boardname/remoterefresh', function(req, res){
    var boardname = req.param('boardname')
    function refreshHandler(data){
        setTimeout(function(){
            res.write('data: '+data+'\n\n');
        }, 1000)
    }
    rr.on("refresh-"+boardname, refreshHandler);

    req.socket.setTimeout(Infinity);

    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    });

    res.write('\n');

    req.on('close', function(){
        console.log('closed')
        rr.removeListener("refresh-"+boardname, refreshHandler);
    });
});

Basically removeListener will look up the given function by reference, if it found that function it will remove it from the event hander.

Smyth answered 27/5, 2014 at 16:0 Comment(1)
thanks man. you are the life saver :) it was joke. but I found solution of my problemChamaeleon
D
7

To avoid referencing the anonymous listener callback function, you can dangerously wipe registered listeners with the emitter.removeAllListeners method:

rr.removeAllListeners("refresh-"+boardname)

Be aware that this approach can easily result in unintended side-effects (deregistering listeners registered elsewhere in the codebase), and should be reserved for "wipe the slate clean" use cases (eg: Testing)

Demonstrator answered 5/9, 2019 at 0:37 Comment(2)
note that rr.removeAllListeners (in the plural) is the correct nameEmmerich
I also found I needed to use removeAllListeners, when removeListener didn't seem to recognise a method name inside a class which was also bound with function.bind(this), so perhaps that doesn't work.Stumer

© 2022 - 2024 — McMap. All rights reserved.