1+ /**
2+ * @license
3+ * Copyright Google Inc. All Rights Reserved.
4+ *
5+ * Use of this source code is governed by an MIT-style license that can be
6+ * found in the LICENSE file at https://angular.io/license
7+ */
8+
9+ import * as Rx from 'rxjs/Rx' ;
10+
11+ ( Zone as any ) . __load_patch ( 'rxjs' , ( global : any , Zone : ZoneType , api : any ) => {
12+ const symbol : ( symbolString : string ) => string = ( Zone as any ) . __symbol__ ;
13+ const subscribeSource = 'rxjs.subscribe' ;
14+ const nextSource = 'rxjs.Subscriber.next' ;
15+ const errorSource = 'rxjs.Subscriber.error' ;
16+ const completeSource = 'rxjs.Subscriber.complete' ;
17+ const unsubscribeSource = 'rxjs.Subscriber.unsubscribe' ;
18+ const teardownSource = 'rxjs.Subscriber.teardownLogic' ;
19+
20+ const patchObservableInstance = function ( observable : any ) {
21+ observable . _zone = Zone . current ;
22+ // patch inner function this._subscribe to check
23+ // SubscriptionZone is same with ConstuctorZone or not
24+ if ( observable . _subscribe && typeof observable . _subscribe === 'function' &&
25+ ! observable . _originalSubscribe ) {
26+ observable . _originalSubscribe = observable . _subscribe ;
27+ observable . _subscribe = _patchedSubscribe ;
28+ }
29+ } ;
30+
31+ const _patchedSubscribe = function ( ) {
32+ const currentZone = Zone . current ;
33+ const _zone = this . _zone ;
34+
35+ const args = Array . prototype . slice . call ( arguments ) ;
36+ const subscriber = args . length > 0 ? args [ 0 ] : undefined ;
37+ // also keep currentZone in Subscriber
38+ // for later Subscriber.next/error/complete method
39+ if ( subscriber && ! subscriber . _zone ) {
40+ subscriber . _zone = currentZone ;
41+ }
42+ // _subscribe should run in ConstructorZone
43+ // but for performance concern, we should check
44+ // whether ConsturctorZone === Zone.current here
45+ const tearDownLogic = _zone !== Zone . current ?
46+ _zone . run ( this . _originalSubscribe , this , args , subscribeSource ) :
47+ this . _originalSubscribe . apply ( this , args ) ;
48+ if ( tearDownLogic && typeof tearDownLogic === 'function' ) {
49+ const patchedTearDownLogic = function ( ) {
50+ // tearDownLogic should also run in ConstructorZone
51+ // but for performance concern, we should check
52+ // whether ConsturctorZone === Zone.current here
53+ if ( _zone && _zone !== Zone . current ) {
54+ return _zone . run ( tearDownLogic , this , arguments , teardownSource ) ;
55+ } else {
56+ return tearDownLogic . apply ( this , arguments ) ;
57+ }
58+ } ;
59+ return patchedTearDownLogic ;
60+ }
61+ return tearDownLogic ;
62+ } ;
63+
64+ const patchObservable = function ( Rx : any , observableType : string ) {
65+ const symbolObservable = symbol ( observableType ) ;
66+
67+ const Observable = Rx [ observableType ] ;
68+ if ( ! Observable || Observable [ symbolObservable ] ) {
69+ // the subclass of Observable not loaded or have been patched
70+ return ;
71+ }
72+
73+ // monkey-patch Observable to save the
74+ // current zone as ConstructorZone
75+ const patchedObservable : any = Rx [ observableType ] = function ( ) {
76+ Observable . apply ( this , arguments ) ;
77+ patchObservableInstance ( this ) ;
78+ return this ;
79+ } ;
80+
81+ patchedObservable . prototype = Observable . prototype ;
82+ patchedObservable [ symbolObservable ] = Observable ;
83+
84+ Object . keys ( Observable ) . forEach ( key => {
85+ patchedObservable [ key ] = Observable [ key ] ;
86+ } ) ;
87+
88+ const ObservablePrototype : any = Observable . prototype ;
89+ const symbolSubscribe = symbol ( 'subscribe' ) ;
90+
91+ if ( ! ObservablePrototype [ symbolSubscribe ] ) {
92+ const subscribe = ObservablePrototype [ symbolSubscribe ] = ObservablePrototype . subscribe ;
93+ // patch Observable.prototype.subscribe
94+ // if SubscripitionZone is different with ConstructorZone
95+ // we should run _subscribe in ConstructorZone and
96+ // create sinke in SubscriptionZone,
97+ // and tearDown should also run into ConstructorZone
98+ Observable . prototype . subscribe = function ( ) {
99+ const _zone = this . _zone ;
100+ const currentZone = Zone . current ;
101+
102+ // if operator is involved, we should also
103+ // patch the call method to save the Subscription zone
104+ if ( this . operator && _zone && _zone !== currentZone ) {
105+ const call = this . operator . call ;
106+ this . operator . call = function ( ) {
107+ const args = Array . prototype . slice . call ( arguments ) ;
108+ const subscriber = args . length > 0 ? args [ 0 ] : undefined ;
109+ if ( ! subscriber . _zone ) {
110+ subscriber . _zone = currentZone ;
111+ }
112+ return _zone . run ( call , this , args , subscribeSource ) ;
113+ } ;
114+ }
115+ const result = subscribe . apply ( this , arguments ) ;
116+ // the result is the subscriber sink,
117+ // we save the current Zone here
118+ if ( ! result . _zone ) {
119+ result . _zone = currentZone ;
120+ }
121+ return result ;
122+ } ;
123+ }
124+
125+ const symbolLift = symbol ( 'lift' ) ;
126+ if ( ! ObservablePrototype [ symbolLift ] ) {
127+ const lift = ObservablePrototype [ symbolLift ] = ObservablePrototype . lift ;
128+
129+ // patch lift method to save ConstructorZone of Observable
130+ Observable . prototype . lift = function ( ) {
131+ const observable = lift . apply ( this , arguments ) ;
132+ patchObservableInstance ( observable ) ;
133+
134+ return observable ;
135+ } ;
136+ }
137+
138+ const symbolCreate = symbol ( 'create' ) ;
139+ if ( ! patchedObservable [ symbolCreate ] ) {
140+ const create = patchedObservable [ symbolCreate ] = Observable . create ;
141+ // patch create method to save ConstructorZone of Observable
142+ Rx . Observable . create = function ( ) {
143+ const observable = create . apply ( this , arguments ) ;
144+ patchObservableInstance ( observable ) ;
145+
146+ return observable ;
147+ } ;
148+ }
149+ } ;
150+
151+ const patchSubscriber = function ( ) {
152+ const Subscriber = Rx . Subscriber ;
153+
154+ const next = Subscriber . prototype . next ;
155+ const error = Subscriber . prototype . error ;
156+ const complete = Subscriber . prototype . complete ;
157+ const unsubscribe = Subscriber . prototype . unsubscribe ;
158+
159+ // patch Subscriber.next to make sure it run
160+ // into SubscriptionZone
161+ Subscriber . prototype . next = function ( ) {
162+ const currentZone = Zone . current ;
163+ const subscriptionZone = this . _zone ;
164+
165+ // for performance concern, check Zone.current
166+ // equal with this._zone(SubscriptionZone) or not
167+ if ( subscriptionZone && subscriptionZone !== currentZone ) {
168+ return subscriptionZone . run ( next , this , arguments , nextSource ) ;
169+ } else {
170+ return next . apply ( this , arguments ) ;
171+ }
172+ } ;
173+
174+ Subscriber . prototype . error = function ( ) {
175+ const currentZone = Zone . current ;
176+ const subscriptionZone = this . _zone ;
177+
178+ // for performance concern, check Zone.current
179+ // equal with this._zone(SubscriptionZone) or not
180+ if ( subscriptionZone && subscriptionZone !== currentZone ) {
181+ return subscriptionZone . run ( error , this , arguments , errorSource ) ;
182+ } else {
183+ return error . apply ( this , arguments ) ;
184+ }
185+ } ;
186+
187+ Subscriber . prototype . complete = function ( ) {
188+ const currentZone = Zone . current ;
189+ const subscriptionZone = this . _zone ;
190+
191+ // for performance concern, check Zone.current
192+ // equal with this._zone(SubscriptionZone) or not
193+ if ( subscriptionZone && subscriptionZone !== currentZone ) {
194+ return subscriptionZone . run ( complete , this , arguments , completeSource ) ;
195+ } else {
196+ return complete . apply ( this , arguments ) ;
197+ }
198+ } ;
199+
200+ Subscriber . prototype . unsubscribe = function ( ) {
201+ const currentZone = Zone . current ;
202+ const subscriptionZone = this . _zone ;
203+
204+ // for performance concern, check Zone.current
205+ // equal with this._zone(SubscriptionZone) or not
206+ if ( subscriptionZone && subscriptionZone !== currentZone ) {
207+ return subscriptionZone . run ( unsubscribe , this , arguments , unsubscribeSource ) ;
208+ } else {
209+ return unsubscribe . apply ( this , arguments ) ;
210+ }
211+ } ;
212+ } ;
213+
214+ const patchObservableFactoryCreator = function ( obj : any , factoryName : string ) {
215+ const symbolFactory : string = symbol ( factoryName ) ;
216+ if ( obj [ symbolFactory ] ) {
217+ return ;
218+ }
219+ const factoryCreator : any = obj [ symbolFactory ] = obj [ factoryName ] ;
220+ obj [ factoryName ] = function ( ) {
221+ const factory : any = factoryCreator . apply ( this , arguments ) ;
222+ return function ( ) {
223+ const observable = factory . apply ( this , arguments ) ;
224+ patchObservableInstance ( observable ) ;
225+ return observable ;
226+ } ;
227+ } ;
228+ } ;
229+
230+ patchObservable ( Rx , 'Observable' ) ;
231+ patchSubscriber ( ) ;
232+ patchObservableFactoryCreator ( Rx . Observable , 'bindCallback' ) ;
233+ patchObservableFactoryCreator ( Rx . Observable , 'bindNodeCallback' ) ;
234+ } ) ;
0 commit comments