diff --git a/NON-STANDARD-APIS.md b/NON-STANDARD-APIS.md index f68bc3ddc..978735f4b 100644 --- a/NON-STANDARD-APIS.md +++ b/NON-STANDARD-APIS.md @@ -103,3 +103,61 @@ for example, if you want to add MediaQuery patch, you should do like this. ``` + +* rxjs + +`zone.js` also provide a `rxjs` patch to make sure rxjs Observable/Subscription/Operator run in correct zone. +for detail please refer to [pull request 843](https://github.com/angular/zone.js/pull/843), the following sample code describe the idea. + +``` +const constructorZone = Zone.current.fork({name: 'constructor'}); +const subscriptionZone = Zone.current.fork({name: 'subscription'}); +const operatorZone = Zone.current.fork({name: 'operator'}); + +let observable; +let subscriber; +constructorZone.run(() => { + observable = new Observable((_subscriber) => { + subscriber = _subscriber; + console.log('current zone when construct observable:', Zone.current.name); // will output constructor. + return () => { + console.log('current zone when unsubscribe observable:', Zone.current.name); // will output constructor. + } + }); +}); + +subscriptionZone.run(() => { + observable.subscribe(() => { + console.log('current zone when subscription next', Zone.current.name); // will output subscription. + }, () => { + console.log('current zone when subscription error', Zone.current.name); // will output subscription. + }, () => { + console.log('current zone when subscription complete', Zone.current.name); // will output subscription. + }); +}); + +operatorZone.run(() => { + observable.map(() => { + console.log('current zone when map operator', Zone.current.name); // will output operator. + }); +}); +``` + +currently basically all `rxjs` API include + +- Observable +- Subscription +- Subscriber +- Operators +- Scheduler + +are patched, so they will run in the correct zone. + +## Usage. + +for example, in angular application, you can load this patch in your `app.module.ts`. + +``` +import 'zone.js/dist/zone-patch-rxjs'; +``` + diff --git a/lib/rxjs/rxjs.ts b/lib/rxjs/rxjs.ts index 1e14147b8..23d5287a9 100644 --- a/lib/rxjs/rxjs.ts +++ b/lib/rxjs/rxjs.ts @@ -340,7 +340,7 @@ import {rxSubscriber} from 'rxjs/symbol/rxSubscriber'; const action = workArgs.length > 0 ? workArgs[0] : undefined; const scheduleZone = action && action[zoneSymbol]; if (scheduleZone && scheduleZone !== Zone.current) { - return scheduleZone.run(work, this, arguments); + return scheduleZone.runGuarded(work, this, arguments); } else { return work.apply(this, arguments); } diff --git a/test/rxjs/rxjs.asap.spec.ts b/test/rxjs/rxjs.asap.spec.ts new file mode 100644 index 000000000..1931bab8e --- /dev/null +++ b/test/rxjs/rxjs.asap.spec.ts @@ -0,0 +1,51 @@ +/** + * @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 + */ + +import * as Rx from 'rxjs/Rx'; +import {asyncTest} from '../test-util'; + +describe('Scheduler.asap', () => { + let log: string[]; + let errorCallback: Function; + const constructorZone: Zone = Zone.root.fork({ + name: 'Constructor Zone', + onHandleError: (delegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, error: Error) => { + log.push('error' + error.message); + const result = delegate.handleError(targetZone, error); + errorCallback && errorCallback(); + return false; + } + }); + + beforeEach(() => { + log = []; + }); + + it('scheduler asap error should run in correct zone', asyncTest((done: any) => { + let observable: any; + constructorZone.run(() => { + observable = Rx.Observable.of(1, 2, 3).observeOn(Rx.Scheduler.asap); + }); + + errorCallback = () => { + expect(log).toEqual(['erroroops']); + setTimeout(done, 0); + }; + + Zone.root.run(() => { + observable + .map((value: number) => { + if (value === 3) { + throw new Error('oops'); + } + return value; + }) + .subscribe((value: number) => {}); + }); + }, Zone.root)); +}); \ No newline at end of file diff --git a/test/rxjs/rxjs.spec.ts b/test/rxjs/rxjs.spec.ts index 0515a3ffd..8a42b0fe2 100644 --- a/test/rxjs/rxjs.spec.ts +++ b/test/rxjs/rxjs.spec.ts @@ -7,6 +7,7 @@ */ import '../../lib/rxjs/rxjs'; import './rxjs.common.spec'; +import './rxjs.asap.spec'; import './rxjs.bindCallback.spec'; import './rxjs.bindNodeCallback.spec'; import './rxjs.combineLatest.spec';