5b084d9d6251ec46eff785aa74b5fe70877de8c8fe57ed07275d21381e00e3f887b7ad6da682df7f79d1506bc3846ecce6d5201209355910302ce66c58f953 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import { Operator } from '../Operator';
  2. import { Subscriber } from '../Subscriber';
  3. import { Observable } from '../Observable';
  4. import { MonoTypeOperatorFunction, PartialObserver, TeardownLogic } from '../types';
  5. import { noop } from '../util/noop';
  6. import { isFunction } from '../util/isFunction';
  7. /* tslint:disable:max-line-length */
  8. /** @deprecated Use an observer instead of a complete callback */
  9. export function tap<T>(next: null | undefined, error: null | undefined, complete: () => void): MonoTypeOperatorFunction<T>;
  10. /** @deprecated Use an observer instead of an error callback */
  11. export function tap<T>(next: null | undefined, error: (error: any) => void, complete?: () => void): MonoTypeOperatorFunction<T>;
  12. /** @deprecated Use an observer instead of a complete callback */
  13. export function tap<T>(next: (value: T) => void, error: null | undefined, complete: () => void): MonoTypeOperatorFunction<T>;
  14. export function tap<T>(next?: (x: T) => void, error?: (e: any) => void, complete?: () => void): MonoTypeOperatorFunction<T>;
  15. export function tap<T>(observer: PartialObserver<T>): MonoTypeOperatorFunction<T>;
  16. /* tslint:enable:max-line-length */
  17. /**
  18. * Perform a side effect for every emission on the source Observable, but return
  19. * an Observable that is identical to the source.
  20. *
  21. * <span class="informal">Intercepts each emission on the source and runs a
  22. * function, but returns an output which is identical to the source as long as errors don't occur.</span>
  23. *
  24. * ![](do.png)
  25. *
  26. * Returns a mirrored Observable of the source Observable, but modified so that
  27. * the provided Observer is called to perform a side effect for every value,
  28. * error, and completion emitted by the source. Any errors that are thrown in
  29. * the aforementioned Observer or handlers are safely sent down the error path
  30. * of the output Observable.
  31. *
  32. * This operator is useful for debugging your Observables for the correct values
  33. * or performing other side effects.
  34. *
  35. * Note: this is different to a `subscribe` on the Observable. If the Observable
  36. * returned by `tap` is not subscribed, the side effects specified by the
  37. * Observer will never happen. `tap` therefore simply spies on existing
  38. * execution, it does not trigger an execution to happen like `subscribe` does.
  39. *
  40. * ## Example
  41. * Map every click to the clientX position of that click, while also logging the click event
  42. * ```ts
  43. * import { fromEvent } from 'rxjs';
  44. * import { tap, map } from 'rxjs/operators';
  45. *
  46. * const clicks = fromEvent(document, 'click');
  47. * const positions = clicks.pipe(
  48. * tap(ev => console.log(ev)),
  49. * map(ev => ev.clientX),
  50. * );
  51. * positions.subscribe(x => console.log(x));
  52. * ```
  53. *
  54. * @see {@link map}
  55. * @see {@link Observable#subscribe}
  56. *
  57. * @param {Observer|function} [nextOrObserver] A normal Observer object or a
  58. * callback for `next`.
  59. * @param {function} [error] Callback for errors in the source.
  60. * @param {function} [complete] Callback for the completion of the source.
  61. * @return {Observable} An Observable identical to the source, but runs the
  62. * specified Observer or callback(s) for each item.
  63. * @name tap
  64. */
  65. export function tap<T>(nextOrObserver?: PartialObserver<T> | ((x: T) => void),
  66. error?: (e: any) => void,
  67. complete?: () => void): MonoTypeOperatorFunction<T> {
  68. return function tapOperatorFunction(source: Observable<T>): Observable<T> {
  69. return source.lift(new DoOperator(nextOrObserver, error, complete));
  70. };
  71. }
  72. class DoOperator<T> implements Operator<T, T> {
  73. constructor(private nextOrObserver?: PartialObserver<T> | ((x: T) => void),
  74. private error?: (e: any) => void,
  75. private complete?: () => void) {
  76. }
  77. call(subscriber: Subscriber<T>, source: any): TeardownLogic {
  78. return source.subscribe(new TapSubscriber(subscriber, this.nextOrObserver, this.error, this.complete));
  79. }
  80. }
  81. /**
  82. * We need this JSDoc comment for affecting ESDoc.
  83. * @ignore
  84. * @extends {Ignored}
  85. */
  86. class TapSubscriber<T> extends Subscriber<T> {
  87. private _context: any;
  88. private _tapNext: ((value: T) => void) = noop;
  89. private _tapError: ((err: any) => void) = noop;
  90. private _tapComplete: (() => void) = noop;
  91. constructor(destination: Subscriber<T>,
  92. observerOrNext?: PartialObserver<T> | ((value: T) => void),
  93. error?: (e?: any) => void,
  94. complete?: () => void) {
  95. super(destination);
  96. this._tapError = error || noop;
  97. this._tapComplete = complete || noop;
  98. if (isFunction(observerOrNext)) {
  99. this._context = this;
  100. this._tapNext = observerOrNext;
  101. } else if (observerOrNext) {
  102. this._context = observerOrNext;
  103. this._tapNext = observerOrNext.next || noop;
  104. this._tapError = observerOrNext.error || noop;
  105. this._tapComplete = observerOrNext.complete || noop;
  106. }
  107. }
  108. _next(value: T) {
  109. try {
  110. this._tapNext.call(this._context, value);
  111. } catch (err) {
  112. this.destination.error(err);
  113. return;
  114. }
  115. this.destination.next(value);
  116. }
  117. _error(err: any) {
  118. try {
  119. this._tapError.call(this._context, err);
  120. } catch (err) {
  121. this.destination.error(err);
  122. return;
  123. }
  124. this.destination.error(err);
  125. }
  126. _complete() {
  127. try {
  128. this._tapComplete.call(this._context, );
  129. } catch (err) {
  130. this.destination.error(err);
  131. return;
  132. }
  133. return this.destination.complete();
  134. }
  135. }