Skip to content

Commit d27b5bd

Browse files
author
Thijs Busser
committed
Change channel priority sort
This fixes issue #15 where a subscriber with an initial priority of 9 winds up being called after a subscriber with priority 1 which was later added. Instead of manually splicing the subscriber into the array of subscribers the `addSubscriber` and `setPriority` and changing the value of the priority property, subscribers are now sorted using the `sort` function of the array with a custom compare function. This compare function will sort the subscribers based on their `priority` property on the `options` object in descending order. The custom sort method doesn't not manipulate the value of the priorityproperty giving a much more predictable result. The unit tests for the priorities have been update to better test if the sort works as expected. An additional unit test specifically for issue #15 has been added.
1 parent 3cc91d6 commit d27b5bd

3 files changed

Lines changed: 63 additions & 47 deletions

File tree

lib/mediator.js

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -98,24 +98,39 @@
9898
// through the Mediator instance.
9999

100100
Channel.prototype = {
101-
addSubscriber: function(fn, options, context){
102-
var subscriber = new Subscriber(fn, options, context);
101+
// Sort function for sorting the channels based on their priority. The sort will
102+
// place the channel with the highest priority in the first place of the array,
103+
// all other channels will be added in descending order. i.g. a channel with a
104+
// priority of 9 will be placed before a channel with a priority of 3
105+
channelPrioritySort: function(a, b) {
106+
if (a.options.priority > b.options.priority) {
107+
return -1;
108+
} else if (a.options.priority < b.options.priority) {
109+
return 1;
110+
}
111+
return 0;
112+
},
103113

104-
if(options && options.priority !== undefined){
114+
addSubscriber: function(fn, options, context){
115+
// Make sure there is always an options object
116+
if (options == null) {
117+
options = {};
118+
}
119+
if (options.priority == null) {
120+
// If priority is undefined we will add a default priority of 0
121+
options.priority = 0;
122+
} else {
105123
// Cheap hack to either parse as an int or turn it into 0. Runs faster
106124
// in many browsers than parseInt with the benefit that it won't
107125
// return a NaN.
108-
options.priority = options.priority >> 0;
109-
110-
if(options.priority < 0){ options.priority = 0; }
111-
if(options.priority >= this._subscribers.length){ options.priority = this._subscribers.length-1; }
112-
113-
this._subscribers.splice(options.priority, 0, subscriber);
114-
}else{
115-
this._subscribers.push(subscriber);
126+
options.priority = options.priority | 0;
116127
}
117128

129+
var subscriber = new Subscriber(fn, options, context);
118130
subscriber.channel = this;
131+
this._subscribers.push(subscriber);
132+
133+
this._subscribers.sort(this.channelPrioritySort);
119134

120135
return subscriber;
121136
},
@@ -143,23 +158,17 @@
143158
// an array index. It will not search recursively through subchannels.
144159

145160
setPriority: function(identifier, priority){
146-
var oldIndex = 0,
147-
x = 0,
148-
sub, firstHalf, lastHalf, y;
161+
var x = 0,
162+
y = this._subscribers.length;
149163

150-
for(x = 0, y = this._subscribers.length; x < y; x++){
151-
if(this._subscribers[x].id === identifier || this._subscribers[x].fn === identifier){
164+
for(; x<y; x++) {
165+
if (this._subscribers[x].id === identifier || this._subscribers[x].fn === identifier){
166+
this._subscribers[x].priority = priority;
152167
break;
153168
}
154-
oldIndex ++;
155169
}
156170

157-
sub = this._subscribers[oldIndex];
158-
firstHalf = this._subscribers.slice(0, oldIndex);
159-
lastHalf = this._subscribers.slice(oldIndex+1);
160-
161-
this._subscribers = firstHalf.concat(lastHalf);
162-
this._subscribers.splice(priority, 0, sub);
171+
this._subscribers.sort(this.channelPrioritySort);
163172
},
164173

165174
addChannel: function(channel){

test/ChannelSpec.js

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,14 @@ describe("Channel", function() {
6767
it("should be able to set top priority", function(){
6868
var spy = sinon.spy(),
6969
spy2 = sinon.spy(),
70-
spy3 = sinon.spy();
71-
72-
channel.addSubscriber(spy);
73-
channel.addSubscriber(spy2);
74-
channel.addSubscriber(spy3, { priority: 1 });
75-
76-
expect(channel._subscribers[0].fn).to.equal(spy);
77-
expect(channel._subscribers[1].fn).to.equal(spy3);
78-
expect(channel._subscribers[2].fn).to.equal(spy2);
70+
spy3 = sinon.spy(),
71+
idA = channel.addSubscriber(spy, { priority: 1}).id,
72+
idB = channel.addSubscriber(spy2).id,
73+
idC = channel.addSubscriber(spy3, { priority: 3 }).id;
74+
75+
expect(channel._subscribers[0].id).to.equal(idC);
76+
expect(channel._subscribers[1].id).to.equal(idA);
77+
expect(channel._subscribers[2].id).to.equal(idB);
7978
});
8079

8180
it("should be able to set arbitrary priority", function(){
@@ -87,26 +86,34 @@ describe("Channel", function() {
8786
channel.addSubscriber(spy2);
8887
channel.addSubscriber(spy3, { priority: 1 });
8988

90-
expect(channel._subscribers[0].fn).to.equal(spy);
91-
expect(channel._subscribers[1].fn).to.equal(spy3);
89+
expect(channel._subscribers[0].fn).to.equal(spy3);
90+
expect(channel._subscribers[1].fn).to.equal(spy);
9291
expect(channel._subscribers[2].fn).to.equal(spy2);
9392
});
9493

9594
it("should be able to change priority after adding it", function(){
9695
var spy = sinon.spy(),
9796
spy2 = sinon.spy(),
98-
spy3 = sinon.spy();
97+
spy3 = sinon.spy(),
98+
idA = channel.addSubscriber(spy, { num: 1 }).id,
99+
idB = channel.addSubscriber(spy2, { num: 2 }).id,
100+
idC = channel.addSubscriber(spy3, { num: 3 }).id;
99101

100-
var sub = channel.addSubscriber(spy, { num: 1 });
101-
channel.addSubscriber(spy2, { num: 2 });
102-
channel.addSubscriber(spy3, { num: 3 });
102+
channel.setPriority(idA, 2);
103103

104-
channel.setPriority(sub.id, 2);
104+
expect(channel._subscribers[0].id).to.equal(idA);
105+
expect(channel._subscribers[1].id).to.equal(idB);
106+
expect(channel._subscribers[2].id).to.equal(idC);
105107

106-
expect(channel._subscribers[0].fn).to.equal(spy2);
107-
expect(channel._subscribers[1].fn).to.equal(spy3);
108-
expect(channel._subscribers[2].fn).to.equal(spy);
108+
});
109+
it("should keep the priorities as initially set (issue #15)", function() {
110+
var spy = sinon.spy(),
111+
spy2 = sinon.spy(),
112+
idA = channel.addSubscriber(spy, {priority: 9}).id,
113+
idB = channel.addSubscriber(spy, {priority: 1}).id;
109114

115+
expect(channel._subscribers[0].id).to.equal(idA);
116+
expect(channel._subscribers[1].id).to.equal(idB);
110117
});
111118
});
112119

@@ -184,13 +191,13 @@ describe("Channel", function() {
184191
var spy = sinon.spy(),
185192
spy2 = sinon.spy(),
186193
spy3 = sinon.spy();
187-
194+
188195
channel.addSubscriber(spy);
189196
var sub2 = channel.addSubscriber(spy2);
190197
expect(channel._subscribers.length).to.equal(2);
191198
channel.addSubscriber(spy3);
192199
expect(channel._subscribers.length).to.equal(3);
193-
200+
194201
channel.removeSubscriber(sub2.id);
195202
expect(channel._subscribers.length).to.equal(2);
196203
expect(channel._subscribers[0].fn).to.equal(spy);
@@ -268,7 +275,7 @@ describe("Channel", function() {
268275
expect(spy).calledWith(data[0]);
269276
expect(spy2).calledWith(data[0]);
270277
});
271-
278+
272279
it("should call all matching subscribers with context", function(){
273280
var spy = sinon.spy(),
274281
data = ["data"];
@@ -278,7 +285,7 @@ describe("Channel", function() {
278285

279286
expect(spy).called;
280287
});
281-
288+
282289
it("should call subscribers in predefined priority", function(){
283290
var sub1 = function(){
284291
this.a += "1";

test/MediatorSpec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ describe("Mediator", function() {
268268
sub = mediator.subscribe("test", spy),
269269
sub2 = mediator.subscribe("test", spy2);
270270

271-
sub2.update({ options: { priority: 0 } });
271+
sub2.update({ options: { priority: 1 } });
272272

273273
expect(mediator.getChannel("test")._subscribers[0].id).to.equal(sub2.id);
274274
expect(mediator.getChannel("test")._subscribers[1].id).to.equal(sub.id);

0 commit comments

Comments
 (0)