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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | 1 1 1 1 1 1 1 93 31 31 31 31 1 31 31 127 32 32 32 1 32 31 32 1 32 1 96 1 96 1 1 96 96 96 96 96 96 1 194 194 194 1 96 96 96 96 96 194 194 1 77 27 1 168 168 168 168 91 91 80 168 107 107 107 88 88 3 85 19 1 | import {Observable} from '../Observable'; import {ArrayObservable} from '../observable/ArrayObservable'; import {isArray} from '../util/isArray'; import {Scheduler} from '../Scheduler'; import {isScheduler} from '../util/isScheduler'; import {Operator} from '../Operator'; import {Subscriber} from '../Subscriber'; import {tryCatch} from '../util/tryCatch'; import {errorObject} from '../util/errorObject'; import {OuterSubscriber} from '../OuterSubscriber'; import {subscribeToResult} from '../util/subscribeToResult'; /** * Combines the values from this observable with values from observables passed as arguments. This is done by subscribing * to each observable, in order, and collecting an array of each of the most recent values any time any of the observables * emits, then either taking that array and passing it as arguments to an option `project` function and emitting the return * value of that, or just emitting the array of recent values directly if there is no `project` function. * @param {...Observable} observables the observables to combine the source with * @param {function} [project] an optional function to project the values from the combined recent values into a new value for emission. * @returns {Observable} an observable of other projected values from the most recent values from each observable, or an array of each of * the most recent values from each observable. */ export function combineLatest<T, R>(...observables: Array<Observable<any> | Array<Observable<any>> | ((...values: Array<any>) => R)>): Observable<R> { let project: (...values: Array<any>) => R = null; Eif (typeof observables[observables.length - 1] === 'function') { project = <(...values: Array<any>) => R>observables.pop(); } // if the first and only other argument besides the resultSelector is an array // assume it's been called with `combineLatest([obs1, obs2, obs3], project)` if (observables.length === 1 && isArray(observables[0])) { observables = <any>observables[0]; } observables.unshift(this); return new ArrayObservable(observables).lift<T, R>(new CombineLatestOperator<T, R>(project)); } /** * Combines the values from observables passed as arguments. This is done by subscribing * to each observable, in order, and collecting an array of each of the most recent values any time any of the observables * emits, then either taking that array and passing it as arguments to an option `project` function and emitting the return * value of that, or just emitting the array of recent values directly if there is no `project` function. * @param {...Observable} observables the observables to combine * @param {function} [project] an optional function to project the values from the combined recent values into a new value for emission. * @returns {Observable} an observable of other projected values from the most recent values from each observable, or an array of each of * the most recent values from each observable. */ export function combineLatestStatic<T, R>(...observables: Array<any | Observable<any> | Array<Observable<any>> | (((...values: Array<any>) => R)) | Scheduler>): Observable<R> { let project: (...values: Array<any>) => R = null; let scheduler: Scheduler = null; if (isScheduler(observables[observables.length - 1])) { scheduler = <Scheduler>observables.pop(); } if (typeof observables[observables.length - 1] === 'function') { project = <(...values: Array<any>) => R>observables.pop(); } // if the first and only other argument besides the resultSelector is an array // assume it's been called with `combineLatest([obs1, obs2, obs3], project)` if (observables.length === 1 && isArray(observables[0])) { observables = <Array<Observable<any>>>observables[0]; } return new ArrayObservable(observables, scheduler).lift<T, R>(new CombineLatestOperator<T, R>(project)); } export class CombineLatestOperator<T, R> implements Operator<T, R> { constructor(private project?: (...values: Array<any>) => R) { } call(subscriber: Subscriber<R>): Subscriber<T> { return new CombineLatestSubscriber(subscriber, this.project); } } export class CombineLatestSubscriber<T, R> extends OuterSubscriber<T, R> { private active: number = 0; private values: any[] = []; private observables: any[] = []; private toRespond: number[] = []; constructor(destination: Subscriber<R>, private project?: (...values: Array<any>) => R) { super(destination); } protected _next(observable: any) { const toRespond = this.toRespond; toRespond.push(toRespond.length); this.observables.push(observable); } protected _complete() { const observables = this.observables; const len = observables.length; Iif (len === 0) { this.destination.complete(); } else { this.active = len; for (let i = 0; i < len; i++) { const observable = observables[i]; this.add(subscribeToResult(this, observable, observable, i)); } } } notifyComplete(unused: Subscriber<R>): void { if ((this.active -= 1) === 0) { this.destination.complete(); } } notifyNext(observable: any, value: R, outerIndex: number, innerIndex: number) { const values = this.values; values[outerIndex] = value; const toRespond = this.toRespond; if (toRespond.length > 0) { const found = toRespond.indexOf(outerIndex); if (found !== -1) { toRespond.splice(found, 1); } } if (toRespond.length === 0) { const project = this.project; const destination = this.destination; if (project) { const result = tryCatch(project).apply(this, values); if (result === errorObject) { destination.error(errorObject.e); } else { destination.next(result); } } else { destination.next(values); } } } } |