Skip to content

Instantly share code, notes, and snippets.

@othiym23
Last active December 24, 2015 13:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save othiym23/6802613 to your computer and use it in GitHub Desktop.
Save othiym23/6802613 to your computer and use it in GitHub Desktop.
The things I do to keep event emitters safe...
Namespace.prototype.bindEmitter = function (source) {
assert.ok(source.on && source.addListener && source.emit, "can only bind real EEs");
var namespace = this;
var contextName = 'context@' + this.name;
/**
* Attach a context to a listener, and make sure that this hook stays
* attached to the emitter forevermore.
*/
function capturer(on) {
return function captured(event, listener) {
listener[contextName] = namespace.active;
try {
return on.call(this, event, listener);
}
finally {
// old-style streaming overwrites .on and .addListener, so rewrap
if (!this.on.__wrapped) shimmer.wrap(this, 'on', capturer);
if (!this.addListener.__wrapped) shimmer.wrap(this, 'addListener', capturer);
}
};
}
/**
* Evaluate listeners within the CLS contexts in which they were originally
* captured.
*/
function puncher(emit) {
// find all the handlers with attached contexts
function prepare(unwrapped) {
if (typeof unwrapped === 'function' && unwrapped[contextName]) {
return namespace.bind(unwrapped, unwrapped[contextName]);
}
else if (unwrapped && unwrapped.length) {
var replacements = [];
for (var i = 0; i < unwrapped.length; i++) {
var handler = unwrapped[i];
var context = handler[contextName];
if (context) handler = namespace.bind(handler, context);
replacements[i] = handler;
}
return replacements;
}
else {
return unwrapped;
}
}
return function punched(event) {
if (!this._events || !this._events[event]) return emit.apply(this, arguments);
// wrap
var unwrapped = this._events[event];
function releaser(removeListener) {
return function unwrapRemove() {
this._events[event] = unwrapped;
try {
return removeListener.apply(this, arguments);
}
finally {
unwrapped = this._events[event];
this._events[event] = prepare(unwrapped);
}
};
}
shimmer.wrap(this, 'removeListener', releaser);
this._events[event] = prepare(unwrapped);
try {
// apply
return emit.apply(this, arguments);
}
finally {
// reset
shimmer.unwrap(this, 'removeListener');
this._events[event] = unwrapped;
}
};
}
shimmer.wrap(source, 'addListener', capturer);
shimmer.wrap(source, 'on', capturer);
shimmer.wrap(source, 'emit', puncher);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment