@@ -30,9 +30,7 @@ export class Subscription implements SubscriptionLike {
30
30
public closed : boolean = false ;
31
31
32
32
/** @internal */
33
- protected _parent : Subscription = null ;
34
- /** @internal */
35
- protected _parents : Subscription [ ] = null ;
33
+ protected _parentOrParents : Subscription | Subscription [ ] = null ;
36
34
/** @internal */
37
35
private _subscriptions : SubscriptionLike [ ] = null ;
38
36
@@ -53,55 +51,47 @@ export class Subscription implements SubscriptionLike {
53
51
* @return {void }
54
52
*/
55
53
unsubscribe ( ) : void {
56
- let hasErrors = false ;
57
54
let errors : any [ ] ;
58
55
59
56
if ( this . closed ) {
60
57
return ;
61
58
}
62
59
63
- let { _parent , _parents , _unsubscribe, _subscriptions } = ( < any > this ) ;
60
+ let { _parentOrParents , _unsubscribe, _subscriptions } = ( < any > this ) ;
64
61
65
62
this . closed = true ;
66
- this . _parent = null ;
67
- this . _parents = null ;
63
+ this . _parentOrParents = null ;
68
64
// null out _subscriptions first so any child subscriptions that attempt
69
65
// to remove themselves from this subscription will noop
70
66
this . _subscriptions = null ;
71
67
72
- let index = - 1 ;
73
- let len = _parents ? _parents . length : 0 ;
74
-
75
- // if this._parent is null, then so is this._parents, and we
76
- // don't have to remove ourselves from any parent subscriptions.
77
- while ( _parent ) {
78
- _parent . remove ( this ) ;
79
- // if this._parents is null or index >= len,
80
- // then _parent is set to null, and the loop exits
81
- _parent = ++ index < len && _parents [ index ] || null ;
68
+ if ( _parentOrParents instanceof Subscription ) {
69
+ _parentOrParents . remove ( this ) ;
70
+ } else if ( _parentOrParents !== null ) {
71
+ for ( let index = 0 ; index < _parentOrParents . length ; ++ index ) {
72
+ const parent = _parentOrParents [ index ] ;
73
+ parent . remove ( this ) ;
74
+ }
82
75
}
83
76
84
77
if ( isFunction ( _unsubscribe ) ) {
85
78
try {
86
79
_unsubscribe . call ( this ) ;
87
80
} catch ( e ) {
88
- hasErrors = true ;
89
81
errors = e instanceof UnsubscriptionError ? flattenUnsubscriptionErrors ( e . errors ) : [ e ] ;
90
82
}
91
83
}
92
84
93
85
if ( isArray ( _subscriptions ) ) {
94
-
95
- index = - 1 ;
96
- len = _subscriptions . length ;
86
+ let index = - 1 ;
87
+ let len = _subscriptions . length ;
97
88
98
89
while ( ++ index < len ) {
99
90
const sub = _subscriptions [ index ] ;
100
91
if ( isObject ( sub ) ) {
101
92
try {
102
93
sub . unsubscribe ( ) ;
103
94
} catch ( e ) {
104
- hasErrors = true ;
105
95
errors = errors || [ ] ;
106
96
if ( e instanceof UnsubscriptionError ) {
107
97
errors = errors . concat ( flattenUnsubscriptionErrors ( e . errors ) ) ;
@@ -113,7 +103,7 @@ export class Subscription implements SubscriptionLike {
113
103
}
114
104
}
115
105
116
- if ( hasErrors ) {
106
+ if ( errors ) {
117
107
throw new UnsubscriptionError ( errors ) ;
118
108
}
119
109
}
@@ -164,14 +154,34 @@ export class Subscription implements SubscriptionLike {
164
154
}
165
155
}
166
156
167
- if ( subscription . _addParent ( this ) ) {
168
- // Optimize for the common case when adding the first subscription.
169
- const subscriptions = this . _subscriptions ;
170
- if ( subscriptions ) {
171
- subscriptions . push ( subscription ) ;
172
- } else {
173
- this . _subscriptions = [ subscription ] ;
157
+ // Add `this` as parent of `subscription` if that's not already the case.
158
+ let { _parentOrParents } = subscription ;
159
+ if ( _parentOrParents === null ) {
160
+ // If we don't have a parent, then set `subscription._parents` to
161
+ // the `this`, which is the common case that we optimize for.
162
+ subscription . _parentOrParents = this ;
163
+ } else if ( _parentOrParents instanceof Subscription ) {
164
+ if ( _parentOrParents === this ) {
165
+ // The `subscription` already has `this` as a parent.
166
+ return subscription ;
174
167
}
168
+ // If there's already one parent, but not multiple, allocate an
169
+ // Array to store the rest of the parent Subscriptions.
170
+ subscription . _parentOrParents = [ _parentOrParents , this ] ;
171
+ } else if ( _parentOrParents . indexOf ( this ) === - 1 ) {
172
+ // Only add `this` to the _parentOrParents list if it's not already there.
173
+ _parentOrParents . push ( this ) ;
174
+ } else {
175
+ // The `subscription` already has `this` as a parent.
176
+ return subscription ;
177
+ }
178
+
179
+ // Optimize for the common case when adding the first subscription.
180
+ const subscriptions = this . _subscriptions ;
181
+ if ( subscriptions === null ) {
182
+ this . _subscriptions = [ subscription ] ;
183
+ } else {
184
+ subscriptions . push ( subscription ) ;
175
185
}
176
186
177
187
return subscription ;
@@ -192,29 +202,6 @@ export class Subscription implements SubscriptionLike {
192
202
}
193
203
}
194
204
}
195
-
196
- /** @internal */
197
- private _addParent ( parent : Subscription ) : boolean {
198
- let { _parent, _parents } = this ;
199
- if ( _parent === parent ) {
200
- // If the new parent is the same as the current parent, then do nothing.
201
- return false ;
202
- } else if ( ! _parent ) {
203
- // If we don't have a parent, then set this._parent to the new parent.
204
- this . _parent = parent ;
205
- return true ;
206
- } else if ( ! _parents ) {
207
- // If there's already one parent, but not multiple, allocate an Array to
208
- // store the rest of the parent Subscriptions.
209
- this . _parents = [ parent ] ;
210
- return true ;
211
- } else if ( _parents . indexOf ( parent ) === - 1 ) {
212
- // Only add the new parent to the _parents list if it's not already there.
213
- _parents . push ( parent ) ;
214
- return true ;
215
- }
216
- return false ;
217
- }
218
205
}
219
206
220
207
function flattenUnsubscriptionErrors ( errors : any [ ] ) {
0 commit comments