bef721026216968e4d4abde41b8a83fceb498ae5df1cc115746d20530fd8a0fd24c9e48ab00a39b1f9a5477290f5a34c5ade08d9e2af139dd4ad7ef0e039e1 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import { MonoTypeOperatorFunction, ObservableInput } from '../types';
  2. import { operate } from '../util/lift';
  3. import { createOperatorSubscriber } from './OperatorSubscriber';
  4. import { noop } from '../util/noop';
  5. import { innerFrom } from '../observable/innerFrom';
  6. /**
  7. * Returns an Observable that emits all items emitted by the source Observable that are distinct by comparison from previous items.
  8. *
  9. * If a `keySelector` function is provided, then it will project each value from the source observable into a new value that it will
  10. * check for equality with previously projected values. If the `keySelector` function is not provided, it will use each value from the
  11. * source observable directly with an equality check against previous values.
  12. *
  13. * In JavaScript runtimes that support `Set`, this operator will use a `Set` to improve performance of the distinct value checking.
  14. *
  15. * In other runtimes, this operator will use a minimal implementation of `Set` that relies on an `Array` and `indexOf` under the
  16. * hood, so performance will degrade as more values are checked for distinction. Even in newer browsers, a long-running `distinct`
  17. * use might result in memory leaks. To help alleviate this in some scenarios, an optional `flushes` parameter is also provided so
  18. * that the internal `Set` can be "flushed", basically clearing it of values.
  19. *
  20. * ## Examples
  21. *
  22. * A simple example with numbers
  23. *
  24. * ```ts
  25. * import { of, distinct } from 'rxjs';
  26. *
  27. * of(1, 1, 2, 2, 2, 1, 2, 3, 4, 3, 2, 1)
  28. * .pipe(distinct())
  29. * .subscribe(x => console.log(x));
  30. *
  31. * // Outputs
  32. * // 1
  33. * // 2
  34. * // 3
  35. * // 4
  36. * ```
  37. *
  38. * An example using the `keySelector` function
  39. *
  40. * ```ts
  41. * import { of, distinct } from 'rxjs';
  42. *
  43. * of(
  44. * { age: 4, name: 'Foo'},
  45. * { age: 7, name: 'Bar'},
  46. * { age: 5, name: 'Foo'}
  47. * )
  48. * .pipe(distinct(({ name }) => name))
  49. * .subscribe(x => console.log(x));
  50. *
  51. * // Outputs
  52. * // { age: 4, name: 'Foo' }
  53. * // { age: 7, name: 'Bar' }
  54. * ```
  55. * @see {@link distinctUntilChanged}
  56. * @see {@link distinctUntilKeyChanged}
  57. *
  58. * @param keySelector Optional `function` to select which value you want to check as distinct.
  59. * @param flushes Optional `ObservableInput` for flushing the internal HashSet of the operator.
  60. * @return A function that returns an Observable that emits items from the
  61. * source Observable with distinct values.
  62. */
  63. export function distinct<T, K>(keySelector?: (value: T) => K, flushes?: ObservableInput<any>): MonoTypeOperatorFunction<T> {
  64. return operate((source, subscriber) => {
  65. const distinctKeys = new Set();
  66. source.subscribe(
  67. createOperatorSubscriber(subscriber, (value) => {
  68. const key = keySelector ? keySelector(value) : value;
  69. if (!distinctKeys.has(key)) {
  70. distinctKeys.add(key);
  71. subscriber.next(value);
  72. }
  73. })
  74. );
  75. flushes && innerFrom(flushes).subscribe(createOperatorSubscriber(subscriber, () => distinctKeys.clear(), noop));
  76. });
  77. }