11// encapsulates the subscription logic for connecting a component to the redux store, as
22// well as nesting subscriptions of descendant components, so that we can ensure the
33// ancestor components re-render before descendants
4+
5+ const CLEARED = null
6+
7+ function createListenerCollection ( ) {
8+ // the current/next pattern is copied from redux's createStore code.
9+ // TODO: refactor+expose that code to be reusable here?
10+ let current = [ ]
11+ let next = [ ]
12+
13+ return {
14+ clear ( ) {
15+ next = CLEARED
16+ current = CLEARED
17+ } ,
18+
19+ notify ( ) {
20+ current = next
21+ for ( let i = 0 ; i < current . length ; i ++ ) {
22+ current [ i ] ( )
23+ }
24+ } ,
25+
26+ subscribe ( listener ) {
27+ let isSubscribed = true
28+ if ( next === current ) next = current . slice ( )
29+ next . push ( listener )
30+
31+ return function unsubscribe ( ) {
32+ if ( ! isSubscribed || current === CLEARED ) return
33+ isSubscribed = false
34+
35+ if ( next === current ) next = current . slice ( )
36+ next . splice ( next . indexOf ( listener ) , 1 )
37+ }
38+ }
39+ }
40+ }
41+
442export default class Subscription {
543 constructor ( store , parentSub ) {
644 this . subscribe = parentSub
745 ? parentSub . addNestedSub . bind ( parentSub )
846 : store . subscribe . bind ( store )
947
1048 this . unsubscribe = null
11- this . nextListeners = this . currentListeners = [ ]
12- }
13-
14- ensureCanMutateNextListeners ( ) {
15- if ( this . nextListeners === this . currentListeners ) {
16- this . nextListeners = this . currentListeners . slice ( )
17- }
49+ this . listeners = createListenerCollection ( )
1850 }
1951
2052 addNestedSub ( listener ) {
2153 this . trySubscribe ( )
22-
23- let isSubscribed = true
24- this . ensureCanMutateNextListeners ( )
25- this . nextListeners . push ( listener )
26-
27- return function unsubscribe ( ) {
28- if ( ! isSubscribed ) return
29- isSubscribed = false
30-
31- this . ensureCanMutateNextListeners ( )
32- const index = this . nextListeners . indexOf ( listener )
33- this . nextListeners . splice ( index , 1 )
34- }
54+ return this . listeners . subscribe ( listener )
3555 }
3656
3757 notifyNestedSubs ( ) {
38- const listeners = this . currentListeners = this . nextListeners
39- const length = listeners . length
40- for ( let i = 0 ; i < length ; i ++ ) {
41- listeners [ i ] ( )
42- }
58+ this . listeners . notify ( )
4359 }
4460
4561 isSubscribed ( ) {
@@ -55,7 +71,10 @@ export default class Subscription {
5571 tryUnsubscribe ( ) {
5672 if ( this . unsubscribe ) {
5773 this . unsubscribe ( )
74+ this . listeners . clear ( )
5875 }
5976 this . unsubscribe = null
77+ this . subscribe = null
78+ this . listeners = { notify ( ) { } }
6079 }
6180}
0 commit comments