This repository has been archived by the owner on Feb 26, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 407
feat(rxjs): fix #830, monkey patch rxjs to make rxjs run in correct zone #843
Merged
Merged
Changes from 10 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
d37e332
feat(rxjs): fix #830, monkey patch rxjs to make rxjs run in correct zone
JiaLiPassion 0afdb96
make test pass
JiaLiPassion 9b651e1
add karma config
JiaLiPassion 093ffb7
pass compile-esm
JiaLiPassion b129e41
change rxjs to umd
JiaLiPassion 2fc5d46
change spec to pass test
JiaLiPassion da92051
add comment, patch Observable.create
JiaLiPassion 0e5ad22
refactor, not create a new closure _subscribe everytime
JiaLiPassion f56c213
fix set wrong object
JiaLiPassion b238b09
begin to apply observable methods, 1: bindCallback
JiaLiPassion 3889379
fix async scheduler reset zone issue
JiaLiPassion eaebc3a
change require to import
JiaLiPassion f855927
still need require in rxjs.spec
JiaLiPassion 1b4d50c
make build and dist pass test
JiaLiPassion 18d9965
remove meta def
JiaLiPassion 389472e
make import work on both build and dist
JiaLiPassion 696f6cb
continue to add cases
JiaLiPassion e754d4d
Merge branch 'master' into rxjs
mhevery File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,244 @@ | ||
/** | ||
* @license | ||
* Copyright Google Inc. All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
declare let define: any; | ||
(function(root: any, factory: (Rx: any) => any) { | ||
if (typeof exports === 'object' && typeof module !== 'undefined') { | ||
// Node, CommonJS-like | ||
module.exports = factory(require('rxjs')); | ||
} else if (typeof define === 'function' && define.amd) { | ||
// AMD | ||
define(['rxjs'], factory); | ||
} else { | ||
factory(root.Rx); | ||
} | ||
}(typeof window !== 'undefined' && window || typeof self !== 'undefined' && self || global, | ||
(Rx: any) => { | ||
'use strict'; | ||
Zone.__load_patch('rxjs', (global: any, Zone: ZoneType, api: _ZonePrivate) => { | ||
const subscribeSource = 'rxjs.subscribe'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Out of these There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have modified this one. |
||
const nextSource = 'rxjs.Subscriber.next'; | ||
const errorSource = 'rxjs.Subscriber.error'; | ||
const completeSource = 'rxjs.Subscriber.complete'; | ||
const unsubscribeSource = 'rxjs.Subscriber.unsubscribe'; | ||
|
||
const patchObservableInstance = function(observable: any) { | ||
observable._zone = Zone.current; | ||
// patch inner function this._subscribe to check | ||
// SubscriptionZone is same with ConstuctorZone or not | ||
if (observable._subscribe && typeof observable._subscribe === 'function' && | ||
!observable._originalSubscribe) { | ||
observable._originalSubscribe = observable._subscribe; | ||
observable._subscribe = _patchedSubscribe; | ||
} | ||
}; | ||
|
||
const _patchedSubscribe = function() { | ||
const currentZone = Zone.current; | ||
const _zone = this._zone; | ||
|
||
const args = Array.prototype.slice.call(arguments); | ||
const subscriber = args.length > 0 ? args[0] : undefined; | ||
// also keep currentZone in Subscriber | ||
// for later Subscriber.next/error/complete method | ||
if (subscriber && !subscriber._zone) { | ||
subscriber._zone = currentZone; | ||
} | ||
// _subscribe should run in ConstructorZone | ||
// but for performance concern, we should check | ||
// whether ConsturctorZone === Zone.current here | ||
const tearDownLogic = _zone !== Zone.current ? | ||
_zone.run(this._originalSubscribe, this, args) : | ||
this._originalSubscribe.apply(this, args); | ||
if (tearDownLogic && typeof tearDownLogic === 'function') { | ||
const patchedTearDownLogic = function() { | ||
// tearDownLogic should also run in ConstructorZone | ||
// but for performance concern, we should check | ||
// whether ConsturctorZone === Zone.current here | ||
if (_zone && _zone !== Zone.current) { | ||
return _zone.run(tearDownLogic, this, arguments); | ||
} else { | ||
return tearDownLogic.apply(this, arguments); | ||
} | ||
}; | ||
return patchedTearDownLogic; | ||
} | ||
return tearDownLogic; | ||
}; | ||
|
||
const patchObservable = function(Rx: any, observableType: string) { | ||
const symbol = Zone.__symbol__(observableType); | ||
if (Rx[symbol]) { | ||
// has patched | ||
return; | ||
} | ||
|
||
const Observable = Rx[symbol] = Rx[observableType]; | ||
if (!Observable) { | ||
// the subclass of Observable not loaded | ||
return; | ||
} | ||
|
||
// monkey-patch Observable to save the | ||
// current zone as ConstructorZone | ||
const patchedObservable: any = Rx[observableType] = function() { | ||
Observable.apply(this, arguments); | ||
patchObservableInstance(this); | ||
return this; | ||
}; | ||
|
||
patchedObservable.prototype = Observable.prototype; | ||
Object.keys(Observable).forEach(key => { | ||
patchedObservable[key] = Observable[key]; | ||
}); | ||
|
||
const ObservablePrototype: any = Observable.prototype; | ||
const symbolSubscribe = Zone.__symbol__('subscribe'); | ||
|
||
if (!ObservablePrototype[symbolSubscribe]) { | ||
const subscribe = ObservablePrototype[symbolSubscribe] = ObservablePrototype.subscribe; | ||
// patch Observable.prototype.subscribe | ||
// if SubscripitionZone is different with ConstructorZone | ||
// we should run _subscribe in ConstructorZone and | ||
// create sinke in SubscriptionZone, | ||
// and tearDown should also run into ConstructorZone | ||
Observable.prototype.subscribe = function() { | ||
const _zone = this._zone; | ||
const currentZone = Zone.current; | ||
|
||
// if operator is involved, we should also | ||
// patch the call method to save the Subscription zone | ||
if (this.operator && _zone && _zone !== currentZone) { | ||
const call = this.operator.call; | ||
this.operator.call = function() { | ||
const args = Array.prototype.slice.call(arguments); | ||
const subscriber = args.length > 0 ? args[0] : undefined; | ||
if (!subscriber._zone) { | ||
subscriber._zone = currentZone; | ||
} | ||
return _zone.run(call, this, args); | ||
}; | ||
} | ||
const result = subscribe.apply(this, arguments); | ||
// the result is the subscriber sink, | ||
// we save the current Zone here | ||
result._zone = currentZone; | ||
return result; | ||
}; | ||
} | ||
|
||
const symbolLift = Zone.__symbol__('lift'); | ||
if (!ObservablePrototype[symbolLift]) { | ||
const lift = ObservablePrototype[symbolLift] = ObservablePrototype.lift; | ||
|
||
// patch lift method to save ConstructorZone of Observable | ||
Observable.prototype.lift = function() { | ||
const observable = lift.apply(this, arguments); | ||
patchObservableInstance(observable); | ||
|
||
return observable; | ||
}; | ||
} | ||
|
||
const symbolCreate = Zone.__symbol__('create'); | ||
if (!Observable[symbolCreate]) { | ||
const create = Observable[symbolCreate] = Observable.create; | ||
// patch create method to save ConstructorZone of Observable | ||
Rx.Observable.create = function() { | ||
const observable = create.apply(this, arguments); | ||
patchObservableInstance(observable); | ||
|
||
return observable; | ||
}; | ||
} | ||
}; | ||
|
||
const patchSubscriber = function() { | ||
const Subscriber = Rx.Subscriber; | ||
|
||
const next = Subscriber.prototype.next; | ||
const error = Subscriber.prototype.error; | ||
const complete = Subscriber.prototype.complete; | ||
const unsubscribe = Subscriber.prototype.unsubscribe; | ||
|
||
// patch Subscriber.next to make sure it run | ||
// into SubscriptionZone | ||
Subscriber.prototype.next = function() { | ||
const currentZone = Zone.current; | ||
const subscriptionZone = this._zone; | ||
|
||
// for performance concern, check Zone.current | ||
// equal with this._zone(SubscriptionZone) or not | ||
if (subscriptionZone && subscriptionZone !== currentZone) { | ||
return subscriptionZone.run(next, this, arguments, nextSource); | ||
} else { | ||
return next.apply(this, arguments); | ||
} | ||
}; | ||
|
||
Subscriber.prototype.error = function() { | ||
const currentZone = Zone.current; | ||
const subscriptionZone = this._zone; | ||
|
||
// for performance concern, check Zone.current | ||
// equal with this._zone(SubscriptionZone) or not | ||
if (subscriptionZone && subscriptionZone !== currentZone) { | ||
return subscriptionZone.run(error, this, arguments, nextSource); | ||
} else { | ||
return error.apply(this, arguments); | ||
} | ||
}; | ||
|
||
Subscriber.prototype.complete = function() { | ||
const currentZone = Zone.current; | ||
const subscriptionZone = this._zone; | ||
|
||
// for performance concern, check Zone.current | ||
// equal with this._zone(SubscriptionZone) or not | ||
if (subscriptionZone && subscriptionZone !== currentZone) { | ||
return subscriptionZone.run(complete, this, arguments, nextSource); | ||
} else { | ||
return complete.apply(this, arguments); | ||
} | ||
}; | ||
|
||
Subscriber.prototype.unsubscribe = function() { | ||
const currentZone = Zone.current; | ||
const subscriptionZone = this._zone; | ||
|
||
// for performance concern, check Zone.current | ||
// equal with this._zone(SubscriptionZone) or not | ||
if (subscriptionZone && subscriptionZone !== currentZone) { | ||
return subscriptionZone.run(unsubscribe, this, arguments, nextSource); | ||
} else { | ||
return unsubscribe.apply(this, arguments); | ||
} | ||
}; | ||
}; | ||
|
||
const patchObservableFactoryCreator = function(obj: any, factoryName: string) { | ||
const symbol = Zone.__symbol__(factoryName); | ||
if (obj[symbol]) { | ||
return; | ||
} | ||
const factoryCreator: any = obj[symbol] = obj[factoryName]; | ||
obj[factoryName] = function() { | ||
const factory: any = factoryCreator.apply(this, arguments); | ||
return function() { | ||
const observable = factory.apply(this, arguments); | ||
patchObservableInstance(observable); | ||
return observable; | ||
}; | ||
}; | ||
}; | ||
|
||
patchObservable(Rx, 'Observable'); | ||
patchSubscriber(); | ||
patchObservableFactoryCreator(Rx.Observable, 'bindCallback'); | ||
}); | ||
})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of doing it this way we should use rollup umd function to build the UMD.
This should be replaced with simple
import {RX} from 'rxjs'
See: https://rollupjs.org/repl?version=0.45.2&shareable=JTdCJTIybW9kdWxlcyUyMiUzQSU1QiU3QiUyMm5hbWUlMjIlM0ElMjJtYWluLmpzJTIyJTJDJTIyY29kZSUyMiUzQSUyMmltcG9ydCUyMCU3QlJ4JTdEJTIwZnJvbSUyMCdyeGpzJTJGUlgnJTVDbiU1Q24lMkYlMkYlMjBkbyUyMHNvbWV0aGluZyUyMCUyMiU3RCU1RCUyQyUyMm9wdGlvbnMlMjIlM0ElN0IlMjJmb3JtYXQlMjIlM0ElMjJ1bWQlMjIlMkMlMjJtb2R1bGVOYW1lJTIyJTNBJTIybXlCdW5kbGUlMjIlMkMlMjJnbG9iYWxzJTIyJTNBJTdCJTdEJTJDJTIybW9kdWxlSWQlMjIlM0ElMjIlMjIlN0QlMkMlMjJleGFtcGxlJTIyJTNBbnVsbCU3RA==
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed it into
import * as Rx from 'rxjs/Rx'