Skip to content

Commit 1d1991a

Browse files
committed
Merge pull request #153 from sysdea-libs/fix-skipping-observers-alt
Iterate over copy of observers for notifyObservers [Fixes #151]
2 parents c5ecd4f + 7129af7 commit 1d1991a

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

src/change-observer.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ class ChangeObserver {
2727
if (this.__observers.length > 0) {
2828
var currentValues = Immutable.Map()
2929

30-
this.__observers.forEach(entry => {
30+
this.__observers.slice(0).forEach(entry => {
31+
if (entry.unwatched) {
32+
return
33+
}
3134
var getter = entry.getter
3235
var code = hashCode(getter)
3336
var prevState = this.__prevState
@@ -65,13 +68,15 @@ class ChangeObserver {
6568
var entry = {
6669
getter: getter,
6770
handler: handler,
71+
unwatched: false,
6872
}
6973
this.__observers.push(entry)
7074
// return unwatch function
7175
return () => {
7276
// TODO: untrack from change emitter
7377
var ind = this.__observers.indexOf(entry)
7478
if (ind > -1) {
79+
entry.unwatched = true
7580
this.__observers.splice(ind, 1)
7681
}
7782
}

tests/change-observer-tests.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,46 @@ describe('ChangeObserver', () => {
7878
expect(mockFn2.calls.count()).toBe(1)
7979
})
8080
})
81+
82+
it('should not skip observers when handler causes unobserve', () => {
83+
var getter = ['foo', 'bar']
84+
var mockFn = jasmine.createSpy()
85+
var unreg = observer.onChange(getter, () => unreg())
86+
observer.onChange(getter, mockFn)
87+
88+
observer.notifyObservers(initialState.updateIn(getter, x => 2))
89+
90+
expect(mockFn.calls.count()).toBe(1)
91+
})
92+
93+
it('should not call unwatched observers when removed during notify', () => {
94+
var getter = ['foo', 'bar']
95+
var mockFn1 = jasmine.createSpy()
96+
var mockFn2 = jasmine.createSpy()
97+
observer.onChange(getter, () => {
98+
mockFn1()
99+
unreg()
100+
})
101+
var unreg = observer.onChange(getter, mockFn2)
102+
103+
observer.notifyObservers(initialState.updateIn(getter, x => 2))
104+
105+
expect(mockFn1.calls.count()).toBe(1)
106+
expect(mockFn2.calls.count()).toBe(0)
107+
})
108+
109+
it('should not call new observers when handlers attach them', () => {
110+
var getter = ['foo', 'bar']
111+
var mockFn1 = jasmine.createSpy()
112+
var mockFn2 = jasmine.createSpy()
113+
observer.onChange(getter, mockFn1)
114+
observer.onChange(getter, () => observer.onChange(getter, mockFn2))
115+
116+
observer.notifyObservers(initialState.updateIn(getter, x => 2))
117+
118+
expect(mockFn1.calls.count()).toBe(1)
119+
expect(mockFn2.calls.count()).toBe(0)
120+
})
81121
})
82122
// TODO: test the prevValues and registering an observable
83123
})

0 commit comments

Comments
 (0)