How can Node's emitter.removeListener be implemented in ES2015? Adding a callback to an array is easy:
let callbacks = [];
function registerCallback(handler) {
callbacks.push(handler);
});
How can that particular function be removed later, without registerCallback returning some identifier for the function? In other words, unregisterCallback(handler)
should not need any other parameter, and should remove that handler. How would unregisterCallback
check that an anonymous function had been previously added?
Is running handler.toString()
(and potentially a hash function on that) a reliable solution to create an identifier for the function? Or how else should unregisterCallback
iterate through callbacks
to remove that particular element? (Or find the appropriate key in an object or function in a Set.)
mySet.add(function foo() { return 'a'})
mySet.has(function foo() { return 'a'}) // false
The usual solution is to pass the function itself as argument to the unregisterCallback
function. That's what's done in jQuery for example.
So the unregisterCallback
function just has to use indexOf
to find the index of the callback:
function unregisterCallback(handler) {
var index = callbacks.indexOf(handler);
if (~index) callbacks.splice(index, 1);
}
Of course it means the user code must keep the function, it can't be an function defined in the call to registerCallback
.
This doesn't work:
registerCallback(function foo() { return 'a'});
// later...
unregisterCallback(function foo() { return 'a'}); // this is a different function
This works:
function foo(){
return 'a'
}
registerCallback(foo);
// later...
unregisterCallback(foo); // it's the same function
You can also provide the ability to remove by name:
// pass either the function or its name
function unregisterCallback(handler) {
var index = -1;
if (typeof handler==="string") {
for (var i=0; i<callbacks.length; i++) {
if (callbacks[i].name===handler) {
index = i;
break;
}
}
} else {
index = callbacks.indexOf(handler);
}
if (~index) callbacks.splice(index, 1);
}
registerCallback(function foo() { return 'a'});
unregisterCallback("foo");
But the responsibility of name unicity is then in the user code realm, which may be OK, or not, depending on your application.
You can go for a design where the event emitter returns a callable that will update internal state:
const dispose = sleep.on('sheep', ::sleep.tick)
sleep.once('baanough', dispose)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With