remove promiseemitter, properly handle synchronous emits, add tests

This commit is contained in:
Joe Fleming 2014-08-06 13:46:32 -07:00
parent 74d5a3efa5
commit bd178e195c
2 changed files with 47 additions and 15 deletions

View file

@ -1,8 +1,9 @@
define(function (require) {
var _ = require('lodash');
return function EventsProvider(Private, PromiseEmitter) {
return function EventsProvider(Private, Promise, Notifier) {
var BaseObject = Private(require('factories/base_object'));
var notify = new Notifier({ location: 'EventEmitter' });
_.inherits(Events, BaseObject);
function Events() {
@ -17,16 +18,23 @@ define(function (require) {
* @returns {PromiseEmitter}
*/
Events.prototype.on = function (name, handler) {
var self = this;
if (!_.isArray(this._listeners[name])) {
this._listeners[name] = [];
}
return new PromiseEmitter(function (resolve, reject, defer) {
defer._handler = handler;
self._listeners[name].push(defer);
}, handler);
var listener = {
defer: Promise.defer(),
handler: handler
};
// capture then's promise, attach it to the listener
listener.newDeferPromise = listener.defer.promise.then(function recurse(value) {
listener.defer = Promise.defer();
listener.newDeferPromise = listener.defer.promise.then(recurse);
Promise.try(handler, [value]).catch(notify.fatal);
});
this._listeners[name].push(listener);
};
/**
@ -47,8 +55,8 @@ define(function (require) {
if (!handler) {
delete this._listeners[name];
} else {
this._listeners[name] = _.filter(this._listeners[name], function (defer) {
return handler !== defer._handler;
this._listeners[name] = _.filter(this._listeners[name], function (listener) {
return handler !== listener.handler;
});
}
};
@ -59,14 +67,22 @@ define(function (require) {
* @param {mixed} args The args to pass along to the handers
* @returns {void}
*/
Events.prototype.emit = function () {
var args = Array.prototype.slice.call(arguments);
var name = args.shift();
Events.prototype.emit = function (name, value) {
// var args = Array.prototype.slice.call(arguments);
// var name = args.shift();
if (this._listeners[name]) {
// We need to empty the array when we resolve the listners. PromiseEmitter
// will regenerate the listners array with new promises.
_.each(this._listeners[name].splice(0), function (defer) {
defer.resolve.apply(defer, args);
_.each(this._listeners[name], function resolveListener(listener) {
if (listener.defer.resolved) {
// wait for listener.defer to be re-written
listener.newDeferPromise.then(function () {
resolveListener(listener);
});
} else {
listener.defer.resolve(value);
listener.defer.resolved = true;
}
});
}
};

View file

@ -7,7 +7,7 @@ define(function (require) {
// Load kibana
require('index');
describe('State Management', function () {
describe.only('State Management', function () {
describe('Events', function () {
var $rootScope;
var Events;
@ -80,6 +80,22 @@ define(function (require) {
sinon.assert.notCalled(handler1);
});
it('should handle mulitple identical emits in the same tick', function () {
var obj = new Events();
var handler1 = sinon.stub();
obj.on('test', handler1);
obj.emit('test', 'one');
obj.emit('test', 'two');
obj.emit('test', 'three');
$rootScope.$apply();
expect(handler1.callCount).to.be(3);
expect(handler1.getCall(0).calledWith('one')).to.be(true);
expect(handler1.getCall(1).calledWith('two')).to.be(true);
expect(handler1.getCall(2).calledWith('three')).to.be(true);
});
});
});