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 | 1 1 1 1 1 12 1 12 12 12 12 1 12 1 1 12 12 1 12 12 12 12 12 12 2 2 1 22 22 22 12 12 1 1 11 4 2 2 1 1 1 2 3 10 10 1 7 7 5 5 2 1 | import {Observable} from '../Observable'; import {Operator} from '../Operator'; import {Subscriber} from '../Subscriber'; import {tryCatch} from '../util/tryCatch'; import {errorObject} from '../util/errorObject'; import {EmptyError} from '../util/EmptyError'; /** * Returns an Observable that emits only the last item emitted by the source Observable. * It optionally takes a predicate function as a parameter, in which case, rather than emitting * the last item from the source Observable, the resulting Observable will emit the last item * from the source Observable that satisfies the predicate. * * <img src="./img/last.png" width="100%"> * * @param {function} predicate - the condition any source emitted item has to satisfy. * @returns {Observable} an Observable that emits only the last item satisfying the given condition * from the source, or an NoSuchElementException if no such items are emitted. * @throws - Throws if no items that match the predicate are emitted by the source Observable. */ export function last<T, R>(predicate?: (value: T, index: number, source: Observable<T>) => boolean, resultSelector?: (value: T, index: number) => R, defaultValue?: R): Observable<T> | Observable<R> { return this.lift(new LastOperator(predicate, resultSelector, defaultValue, this)); } class LastOperator<T, R> implements Operator<T, R> { constructor(private predicate?: (value: T, index: number, source: Observable<T>) => boolean, private resultSelector?: (value: T, index: number) => R, private defaultValue?: any, private source?: Observable<T>) { } call(observer: Subscriber<R>): Subscriber<T> { return new LastSubscriber(observer, this.predicate, this.resultSelector, this.defaultValue, this.source); } } class LastSubscriber<T, R> extends Subscriber<T> { private lastValue: T | R; private hasValue: boolean = false; private index: number = 0; constructor(destination: Subscriber<R>, private predicate?: (value: T, index: number, source: Observable<T>) => boolean, private resultSelector?: (value: T, index: number) => R, private defaultValue?: any, private source?: Observable<T>) { super(destination); if (typeof defaultValue !== 'undefined') { this.lastValue = defaultValue; this.hasValue = true; } } protected _next(value: T): void { const { predicate, resultSelector, destination } = this; const index = this.index++; if (predicate) { let found = tryCatch(predicate)(value, index, this.source); if (found === errorObject) { destination.error(errorObject.e); return; } if (found) { if (resultSelector) { let result = tryCatch(resultSelector)(value, index); if (result === errorObject) { destination.error(errorObject.e); return; } this.lastValue = result; } else { this.lastValue = value; } this.hasValue = true; } } else { this.lastValue = value; this.hasValue = true; } } protected _complete(): void { const destination = this.destination; if (this.hasValue) { destination.next(this.lastValue); destination.complete(); } else { destination.error(new EmptyError); } } } |