-
Notifications
You must be signed in to change notification settings - Fork 4
/
zone-helper.ts
106 lines (88 loc) · 2.77 KB
/
zone-helper.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import { Observable } from 'rxjs/Observable'
import { fromPromise } from 'rxjs/observable/fromPromise'
import { Operator } from 'rxjs/Operator'
import { Subscriber } from 'rxjs/Subscriber'
import { TeardownLogic } from 'rxjs/Subscription'
export class ZoneHelper {
constructor(private firebaseZone?: Zone) {
if (!firebaseZone) {
if (Zone) {
this.firebaseZone = Zone.root.fork({ name: 'firebase' })
}
}
}
runInFirebase<T>(fn: () => T): T {
if (this.firebaseZone) {
return this.firebaseZone.run<T>(fn)
}
return fn()
}
wrapSubscribe<T extends Function>(fn: T): T {
if (this.firebaseZone) {
return this.firebaseZone.wrap(fn, 'firebaseRxJS.Observable.subscribe')
}
return fn
}
wrapPromise<T>(promiseFactory: () => firebase.Promise<T>): Observable<T> {
if (!Zone) {
return fromPromise(this.runInFirebase(promiseFactory) as Promise<T>)
}
return new Observable(subscriber => {
Zone.current.scheduleMacroTask('firebaseRxJS.Promise',
(err: any, res: any) => {
if (err) {
subscriber.error(err)
} else {
subscriber.next(res)
subscriber.complete()
}
}, {},
(task: Task) => {
const promise = this.runInFirebase(promiseFactory) as Promise<T>
promise.then(task.invoke.bind(task, null), task.invoke.bind(task))
},
(task: Task) => {}
)
})
}
createObservable<T>(subscribe: (subscriber: Subscriber<T>) => TeardownLogic): Observable<T> {
const obs = new Observable(this.wrapSubscribe(subscribe))
if (!Zone) {
return obs
}
return obs.lift(new EventTaskOperator())
}
}
class EventTaskOperator<T> implements Operator<T, T> {
call(subscriber: Subscriber<T>, source: any): TeardownLogic {
return source.subscribe(new EventTaskSubscriber(subscriber, Zone.current))
}
}
class EventTaskSubscriber<T> extends Subscriber<T> {
nextTask: EventTask
constructor(destination: Subscriber<T>, private zone: Zone) {
super(destination)
this.nextTask = this.zone.scheduleEventTask(
'firebaseRxJS.Observable.next',
(val: T) => this.destination.next!(val),
{},
() => {},
() => {},
)
this.add(() => this.zone.cancelTask(this.nextTask))
}
protected _next(value: T): void {
const { nextTask } = this
this.zone.run(nextTask.invoke, nextTask, [value]);
}
protected _error(err: any): void {
const { destination } = this
this.zone.scheduleMicroTask('firebaseRxJS.Observable.error',
destination.error!.bind(destination, err))
}
protected _complete(): void {
const { destination } = this
this.zone.scheduleMicroTask('firebaseRxJS.Observable.complete',
destination.complete!.bind(destination))
}
}