@@ -28,6 +28,8 @@ declare let define: any;
28
28
29
29
const Observable = Rx . Observable ;
30
30
31
+ // monkey-patch Observable to save the
32
+ // current zone as ConstructorZone
31
33
Rx . Observable = function ( ) {
32
34
Observable . apply ( this , arguments ) ;
33
35
this . _zone = Zone . current ;
@@ -38,38 +40,56 @@ declare let define: any;
38
40
39
41
const subscribe = Observable . prototype . subscribe ;
40
42
const lift = Observable . prototype . lift ;
43
+ const create = Observable . create ;
41
44
45
+ // patch Observable.prototype.subscribe
46
+ // if SubscripitionZone is different with ConstructorZone
47
+ // we should run _subscribe in ConstructorZone and
48
+ // create sinke in SubscriptionZone,
49
+ // and tearDown should also run into ConstructorZone
42
50
Observable . prototype . subscribe = function ( ) {
43
51
const _zone = this . _zone ;
44
52
const currentZone = Zone . current ;
45
53
54
+ // patch inner function this._subscribe to check
55
+ // SubscriptionZone is same with ConstuctorZone or not
46
56
if ( this . _subscribe && typeof this . _subscribe === 'function' ) {
47
57
this . _subscribe . _zone = this . _zone ;
48
58
const _subscribe = this . _subscribe ;
49
59
if ( _zone ) {
50
60
this . _subscribe = function ( ) {
51
61
const args = Array . prototype . slice . call ( arguments ) ;
52
62
const subscriber = args . length > 0 ? args [ 0 ] : undefined ;
63
+ // also keep currentZone in Subscriber
64
+ // for later Subscriber.next/error/complete method
53
65
if ( subscriber && ! subscriber . _zone ) {
54
66
subscriber . _zone = currentZone ;
55
67
}
68
+ // _subscribe should run in ConstructorZone
69
+ // but for performance concern, we should check
70
+ // whether ConsturctorZone === Zone.current here
56
71
const tearDownLogic = _zone !== Zone . current ? _zone . run ( _subscribe , this , args ) :
57
72
_subscribe . apply ( this , args ) ;
58
73
if ( tearDownLogic && typeof tearDownLogic === 'function' ) {
59
- const patchedTeadDownLogic = function ( ) {
74
+ const patchedTearDownLogic = function ( ) {
75
+ // tearDownLogic should also run in ConstructorZone
76
+ // but for performance concern, we should check
77
+ // whether ConsturctorZone === Zone.current here
60
78
if ( _zone && _zone !== Zone . current ) {
61
79
return _zone . run ( tearDownLogic , this , arguments ) ;
62
80
} else {
63
81
return tearDownLogic . apply ( this , arguments ) ;
64
82
}
65
83
} ;
66
- return patchedTeadDownLogic ;
84
+ return patchedTearDownLogic ;
67
85
}
68
86
return tearDownLogic ;
69
87
} ;
70
88
}
71
89
}
72
90
91
+ // if operator is involved, we should also
92
+ // patch the call method to save the Subscription zone
73
93
if ( this . operator && _zone && _zone !== currentZone ) {
74
94
const call = this . operator . call ;
75
95
this . operator . call = function ( ) {
@@ -82,65 +102,88 @@ declare let define: any;
82
102
} ;
83
103
}
84
104
const result = subscribe . apply ( this , arguments ) ;
105
+ // clean up _subscribe._zone to prevent
106
+ // the same _subscribe being used in multiple
107
+ // Observable instances.
85
108
if ( this . _subscribe ) {
86
109
this . _subscribe . _zone = undefined ;
87
110
}
88
- result . _zone = Zone . current ;
111
+ // the result is the subscriber sink,
112
+ // we save the current Zone here
113
+ result . _zone = currentZone ;
89
114
return result ;
90
115
} ;
91
116
117
+ // patch lift method to save ConstructorZone of Observable
92
118
Observable . prototype . lift = function ( ) {
93
119
const observable = lift . apply ( this , arguments ) ;
94
120
observable . _zone = Zone . current ;
95
121
return observable ;
96
122
} ;
97
123
124
+ // patch create method to save ConstructorZone of Observable
125
+ Rx . Observable . create = function ( ) {
126
+ const observable = create . apply ( this , arguments ) ;
127
+ observable . _zone = Zone . current ;
128
+ return observable ;
129
+ } ;
130
+
98
131
const Subscriber = Rx . Subscriber ;
99
132
100
133
const next = Subscriber . prototype . next ;
101
134
const error = Subscriber . prototype . error ;
102
135
const complete = Subscriber . prototype . complete ;
103
136
const unsubscribe = Subscriber . prototype . unsubscribe ;
104
137
138
+ // patch Subscriber.next to make sure it run
139
+ // into SubscriptionZone
105
140
Subscriber . prototype . next = function ( ) {
106
141
const currentZone = Zone . current ;
107
- const observableZone = this . _zone ;
142
+ const subscriptionZone = this . _zone ;
108
143
109
- if ( observableZone && observableZone !== currentZone ) {
110
- return observableZone . run ( next , this , arguments , nextSource ) ;
144
+ // for performance concern, check Zone.current
145
+ // equal with this._zone(SubscriptionZone) or not
146
+ if ( subscriptionZone && subscriptionZone !== currentZone ) {
147
+ return subscriptionZone . run ( next , this , arguments , nextSource ) ;
111
148
} else {
112
149
return next . apply ( this , arguments ) ;
113
150
}
114
151
} ;
115
152
116
153
Subscriber . prototype . error = function ( ) {
117
154
const currentZone = Zone . current ;
118
- const observableZone = this . _zone ;
155
+ const subscriptionZone = this . _zone ;
119
156
120
- if ( observableZone && observableZone !== currentZone ) {
121
- return observableZone . run ( error , this , arguments , errorSource ) ;
157
+ // for performance concern, check Zone.current
158
+ // equal with this._zone(SubscriptionZone) or not
159
+ if ( subscriptionZone && subscriptionZone !== currentZone ) {
160
+ return subscriptionZone . run ( error , this , arguments , nextSource ) ;
122
161
} else {
123
162
return error . apply ( this , arguments ) ;
124
163
}
125
164
} ;
126
165
127
166
Subscriber . prototype . complete = function ( ) {
128
167
const currentZone = Zone . current ;
129
- const observableZone = this . _zone ;
168
+ const subscriptionZone = this . _zone ;
130
169
131
- if ( observableZone && observableZone !== currentZone ) {
132
- return observableZone . run ( complete , this , arguments , completeSource ) ;
170
+ // for performance concern, check Zone.current
171
+ // equal with this._zone(SubscriptionZone) or not
172
+ if ( subscriptionZone && subscriptionZone !== currentZone ) {
173
+ return subscriptionZone . run ( complete , this , arguments , nextSource ) ;
133
174
} else {
134
175
return complete . apply ( this , arguments ) ;
135
176
}
136
177
} ;
137
178
138
179
Subscriber . prototype . unsubscribe = function ( ) {
139
180
const currentZone = Zone . current ;
140
- const observableZone = this . _zone ;
181
+ const subscriptionZone = this . _zone ;
141
182
142
- if ( observableZone && observableZone !== currentZone ) {
143
- return observableZone . run ( unsubscribe , this , arguments , unsubscribeSource ) ;
183
+ // for performance concern, check Zone.current
184
+ // equal with this._zone(SubscriptionZone) or not
185
+ if ( subscriptionZone && subscriptionZone !== currentZone ) {
186
+ return subscriptionZone . run ( unsubscribe , this , arguments , nextSource ) ;
144
187
} else {
145
188
return unsubscribe . apply ( this , arguments ) ;
146
189
}
0 commit comments