Pause RxJS stream based on a value in the stream

前端 未结 6 464
一生所求
一生所求 2021-01-03 23:56

I have a simple component with a single button that starts and pauses a stream of numbers generated by RxJS timer.

import { Component, OnInit } from \'@angul         


        
6条回答
  •  耶瑟儿~
    2021-01-04 00:35

    Here's a custom pause operator that will just accumulate values in a buffer when the pause signal is true, and emit them one by one when it is false.

    Combine it with a simple tap operator to toggle the behavior subject pause signal when the value hits a specific condition, and you have something will pause on button click and also pause when the value meets a condition (multiple of 12 in this case):

    Here is the pause operator:

    function pause(pauseSignal: Observable) {
      return (source: Observable) => Observable.create(observer => {
        const buffer = [];
        let paused = false;
        let error;
        let isComplete = false;
    
        function notify() {
          while (!paused && buffer.length) {
            const value = buffer.shift();
            observer.next(value);
          }
    
          if (!buffer.length && error) {
            observer.error(error);
          }
    
          if (!buffer.length && isComplete) {
            observer.complete();
          }
        }
    
        const subscription = pauseSignal.subscribe(
          p => {
            paused = !p;
            setTimeout(notify, 0);
          },
          e => {
            error = e;
            setTimeout(notify, 0);
          },
          () => {});
    
        subscription.add(source.subscribe(
          v => {
            buffer.push(v);
            notify();
          },
          e => {
            error = e;
            notify();
          },
          () => {
            isComplete = true;
            notify();
          }
        ));
    
        return subscription;
      });
    }
    

    Here is the usage of it:

    const CONDITION = x => (x > 0) && ((x % 12) === 0); // is multiple
    this.active$ = new BehaviorSubject(true);
    const stream$ = timer(500, 500);
    const out$ = stream$.pipe(
      pause(this.active$),
      tap(value => {
        if (CONDITION(value)) {
          this.active$.next(false);
        }
      }));
    
    this.d = out$.subscribe(v => console.log(v));
    

    And a working example: https://stackblitz.com/edit/angular-bvxnbf

提交回复
热议问题