0ddf51ce05072cab4b3de0e8758046e914f69226c0666403e9579db909daf6e388ef921c5272c6f3c4b92ee1cfcbaaae5b5fe62b09578201eb44f36b410b83 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. import { ObservableInput, ObservedValueOf, OperatorFunction } from '../types';
  2. import { switchMap } from './switchMap';
  3. import { operate } from '../util/lift';
  4. // TODO: Generate a marble diagram for these docs.
  5. /**
  6. * Applies an accumulator function over the source Observable where the
  7. * accumulator function itself returns an Observable, emitting values
  8. * only from the most recently returned Observable.
  9. *
  10. * <span class="informal">It's like {@link mergeScan}, but only the most recent
  11. * Observable returned by the accumulator is merged into the outer Observable.</span>
  12. *
  13. * @see {@link scan}
  14. * @see {@link mergeScan}
  15. * @see {@link switchMap}
  16. *
  17. * @param accumulator
  18. * The accumulator function called on each source value.
  19. * @param seed The initial accumulation value.
  20. * @return A function that returns an observable of the accumulated values.
  21. */
  22. export function switchScan<T, R, O extends ObservableInput<any>>(
  23. accumulator: (acc: R, value: T, index: number) => O,
  24. seed: R
  25. ): OperatorFunction<T, ObservedValueOf<O>> {
  26. return operate((source, subscriber) => {
  27. // The state we will keep up to date to pass into our
  28. // accumulator function at each new value from the source.
  29. let state = seed;
  30. // Use `switchMap` on our `source` to do the work of creating
  31. // this operator. Note the backwards order here of `switchMap()(source)`
  32. // to avoid needing to use `pipe` unnecessarily
  33. switchMap(
  34. // On each value from the source, call the accumulator with
  35. // our previous state, the value and the index.
  36. (value: T, index) => accumulator(state, value, index),
  37. // Using the deprecated result selector here as a dirty trick
  38. // to update our state with the flattened value.
  39. (_, innerValue) => ((state = innerValue), innerValue)
  40. )(source).subscribe(subscriber);
  41. return () => {
  42. // Release state on finalization
  43. state = null!;
  44. };
  45. });
  46. }