Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

windowWhen.ts 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import { Operator } from '../Operator';
  2. import { Subscriber } from '../Subscriber';
  3. import { Observable } from '../Observable';
  4. import { Subject } from '../Subject';
  5. import { Subscription } from '../Subscription';
  6. import { OuterSubscriber } from '../OuterSubscriber';
  7. import { InnerSubscriber } from '../InnerSubscriber';
  8. import { subscribeToResult } from '../util/subscribeToResult';
  9. import { OperatorFunction } from '../types';
  10. /**
  11. * Branch out the source Observable values as a nested Observable using a
  12. * factory function of closing Observables to determine when to start a new
  13. * window.
  14. *
  15. * <span class="informal">It's like {@link bufferWhen}, but emits a nested
  16. * Observable instead of an array.</span>
  17. *
  18. * ![](windowWhen.png)
  19. *
  20. * Returns an Observable that emits windows of items it collects from the source
  21. * Observable. The output Observable emits connected, non-overlapping windows.
  22. * It emits the current window and opens a new one whenever the Observable
  23. * produced by the specified `closingSelector` function emits an item. The first
  24. * window is opened immediately when subscribing to the output Observable.
  25. *
  26. * ## Example
  27. * Emit only the first two clicks events in every window of [1-5] random seconds
  28. * ```ts
  29. * import { fromEvent, interval } from 'rxjs';
  30. * import { windowWhen, map, mergeAll, take } from 'rxjs/operators';
  31. *
  32. * const clicks = fromEvent(document, 'click');
  33. * const result = clicks.pipe(
  34. * windowWhen(() => interval(1000 + Math.random() * 4000)),
  35. * map(win => win.pipe(take(2))), // each window has at most 2 emissions
  36. * mergeAll() // flatten the Observable-of-Observables
  37. * );
  38. * result.subscribe(x => console.log(x));
  39. * ```
  40. *
  41. * @see {@link window}
  42. * @see {@link windowCount}
  43. * @see {@link windowTime}
  44. * @see {@link windowToggle}
  45. * @see {@link bufferWhen}
  46. *
  47. * @param {function(): Observable} closingSelector A function that takes no
  48. * arguments and returns an Observable that signals (on either `next` or
  49. * `complete`) when to close the previous window and start a new one.
  50. * @return {Observable<Observable<T>>} An observable of windows, which in turn
  51. * are Observables.
  52. * @method windowWhen
  53. * @owner Observable
  54. */
  55. export function windowWhen<T>(closingSelector: () => Observable<any>): OperatorFunction<T, Observable<T>> {
  56. return function windowWhenOperatorFunction(source: Observable<T>) {
  57. return source.lift(new WindowOperator<T>(closingSelector));
  58. };
  59. }
  60. class WindowOperator<T> implements Operator<T, Observable<T>> {
  61. constructor(private closingSelector: () => Observable<any>) {
  62. }
  63. call(subscriber: Subscriber<Observable<T>>, source: any): any {
  64. return source.subscribe(new WindowSubscriber(subscriber, this.closingSelector));
  65. }
  66. }
  67. /**
  68. * We need this JSDoc comment for affecting ESDoc.
  69. * @ignore
  70. * @extends {Ignored}
  71. */
  72. class WindowSubscriber<T> extends OuterSubscriber<T, any> {
  73. private window: Subject<T>;
  74. private closingNotification: Subscription;
  75. constructor(protected destination: Subscriber<Observable<T>>,
  76. private closingSelector: () => Observable<any>) {
  77. super(destination);
  78. this.openWindow();
  79. }
  80. notifyNext(outerValue: T, innerValue: any,
  81. outerIndex: number, innerIndex: number,
  82. innerSub: InnerSubscriber<T, any>): void {
  83. this.openWindow(innerSub);
  84. }
  85. notifyError(error: any, innerSub: InnerSubscriber<T, any>): void {
  86. this._error(error);
  87. }
  88. notifyComplete(innerSub: InnerSubscriber<T, any>): void {
  89. this.openWindow(innerSub);
  90. }
  91. protected _next(value: T): void {
  92. this.window.next(value);
  93. }
  94. protected _error(err: any): void {
  95. this.window.error(err);
  96. this.destination.error(err);
  97. this.unsubscribeClosingNotification();
  98. }
  99. protected _complete(): void {
  100. this.window.complete();
  101. this.destination.complete();
  102. this.unsubscribeClosingNotification();
  103. }
  104. private unsubscribeClosingNotification(): void {
  105. if (this.closingNotification) {
  106. this.closingNotification.unsubscribe();
  107. }
  108. }
  109. private openWindow(innerSub: InnerSubscriber<T, any> = null): void {
  110. if (innerSub) {
  111. this.remove(innerSub);
  112. innerSub.unsubscribe();
  113. }
  114. const prevWindow = this.window;
  115. if (prevWindow) {
  116. prevWindow.complete();
  117. }
  118. const window = this.window = new Subject<T>();
  119. this.destination.next(window);
  120. let closingNotifier;
  121. try {
  122. const { closingSelector } = this;
  123. closingNotifier = closingSelector();
  124. } catch (e) {
  125. this.destination.error(e);
  126. this.window.error(e);
  127. return;
  128. }
  129. this.add(this.closingNotification = subscribeToResult(this, closingNotifier));
  130. }
  131. }