Skip to content

Commit

Permalink
fix(subscriberCollection): handle cascading calls
Browse files Browse the repository at this point in the history
Fixes #252, Fixes jdanyow/aurelia-computed#12

Handles scenarios where observers have subscriptions that overflow into the 'rest' buckets and calling one observer's subscribers causes another observer's subscribers to be called
  • Loading branch information
jdanyow committed Dec 21, 2015
1 parent 752b1ef commit 5b3ae75
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 15 deletions.
54 changes: 39 additions & 15 deletions src/subscriber-collection.js
Expand Up @@ -53,8 +53,9 @@ function removeSubscriber(context, callable) {
return true;
}

let tempContextsRest = [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null];
let tempCallablesRest = [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null];
let arrayPool1 = [];
let arrayPool2 = [];
let poolUtilization = [];

function callSubscribers(newValue, oldValue) {
let context0 = this._context0;
Expand All @@ -63,12 +64,32 @@ function callSubscribers(newValue, oldValue) {
let callable1 = this._callable1;
let context2 = this._context2;
let callable2 = this._callable2;
let length = !this._contextsRest ? 0 : this._contextsRest.length;
let i = length;
let length = this._contextsRest ? this._contextsRest.length : 0;
let contextsRest;
let callablesRest;
let poolIndex;
let i;
if (length) {
// grab temp arrays from the pool.
poolIndex = poolUtilization.length;
while (poolIndex-- && poolUtilization[poolIndex]) { }
if (poolIndex < 0) {
poolIndex = poolUtilization.length;
contextsRest = [];
callablesRest = [];
poolUtilization.push(true);
arrayPool1.push(contextsRest);
arrayPool2.push(callablesRest);
} else {
poolUtilization[poolIndex] = true;
contextsRest = arrayPool1[poolIndex];
callablesRest = arrayPool2[poolIndex];
}
// copy the contents of the "rest" arrays.
i = length;
while(i--) {
tempContextsRest[i] = this._contextsRest[i];
tempCallablesRest[i] = this._callablesRest[i];
contextsRest[i] = this._contextsRest[i];
callablesRest[i] = this._callablesRest[i];
}
}

Expand All @@ -93,16 +114,19 @@ function callSubscribers(newValue, oldValue) {
context2(newValue, oldValue);
}
}
for (i = 0; i < length; i++) {
let callable = tempCallablesRest[i];
let context = tempContextsRest[i]
if (callable) {
callable.call(context, newValue, oldValue);
} else {
context(newValue, oldValue);
if (length) {
for (i = 0; i < length; i++) {
let callable = callablesRest[i];
let context = contextsRest[i]
if (callable) {
callable.call(context, newValue, oldValue);
} else {
context(newValue, oldValue);
}
contextsRest[i] = null;
callablesRest[i] = null;
}
tempContextsRest[i] = null;
tempCallablesRest[i] = null;
poolUtilization[poolIndex] = false;
}
}

Expand Down
46 changes: 46 additions & 0 deletions test/subscriber-collection.spec.js
@@ -0,0 +1,46 @@
import {subscriberCollection} from '../src/subscriber-collection';

@subscriberCollection()
class Test { }

describe('subscriberCollection', () => {
it('calls subscribers', () => {
let observer = new Test();
let observer2 = new Test();

let callable1 = { call: jasmine.createSpy('call') };
observer.addSubscriber('1', callable1);
let callable2 = { call: jasmine.createSpy('call') };
observer.addSubscriber('2', callable2);
let callable3 = { call: jasmine.createSpy('call') };
observer.addSubscriber('3', callable3);
let callable4 = { call: jasmine.createSpy('call').and.callFake(() => observer2.callSubscribers('new value2', 'old value2')) };
observer.addSubscriber('4', callable4);
let callable5 = { call: jasmine.createSpy('call') };
observer.addSubscriber('5', callable5);

let callable6 = { call: jasmine.createSpy('call') };
observer2.addSubscriber('6', callable6);
let callable7 = { call: jasmine.createSpy('call') };
observer2.addSubscriber('7', callable7);
let callable8 = { call: jasmine.createSpy('call') };
observer2.addSubscriber('8', callable8);
let callable9 = { call: jasmine.createSpy('call') };
observer2.addSubscriber('9', callable9);
let callable10 = { call: jasmine.createSpy('call') };
observer2.addSubscriber('10', callable10);

observer.callSubscribers('new value', 'old value');

expect(callable1.call).toHaveBeenCalledWith('1', 'new value', 'old value');
expect(callable2.call).toHaveBeenCalledWith('2', 'new value', 'old value');
expect(callable3.call).toHaveBeenCalledWith('3', 'new value', 'old value');
expect(callable4.call).toHaveBeenCalledWith('4', 'new value', 'old value');
expect(callable5.call).toHaveBeenCalledWith('5', 'new value', 'old value');
expect(callable6.call).toHaveBeenCalledWith('6', 'new value2', 'old value2');
expect(callable7.call).toHaveBeenCalledWith('7', 'new value2', 'old value2');
expect(callable8.call).toHaveBeenCalledWith('8', 'new value2', 'old value2');
expect(callable9.call).toHaveBeenCalledWith('9', 'new value2', 'old value2');
expect(callable10.call).toHaveBeenCalledWith('10', 'new value2', 'old value2');
});
});

0 comments on commit 5b3ae75

Please sign in to comment.