即使父源流仍发出新值,带有合并的计时器也会停止发出值

时间:2018-12-12 19:48:15

标签: javascript rxjs rxjs6 reactivex

我尝试将我的应用程序的3个流状态合并为1。周期为断开连接<->连接<->已认证。因此,只要应用程序仅连接到服务器,它将尝试每3秒发送一次auth。除非已断开连接或已通过身份验证。

我正在使用rxjs计时器在要合并的流上发送身份验证,如果已通过身份验证,则使用takeUntil停止发送身份验证。但是问题在于,即使要合并的auth $仍然发出响应,合并的auth $仍未发出sendAuth流,而是合并的auth $停止发出新的响应。这是代码:

this._response$ = fromEvent<string>(this._socket, "response")
  .pipe(map(data => JSON.parse(data)));

const disconnect$ = fromEvent(this._socket, "disconnect");
const connect$ = fromEvent(this._socket, "connect");
const auth$ = this._response$.pipe(
  // this stream still emitting even if takeUntil is declared on connect$.
  filter(res => res.action === "authentication" && res.type === "success"),
);

status$ = merge(
  disconnect$.pipe(
    map(() => {
      this._status = statusEnum.OFF;
      return this._status;
    })
  ),
  connect$.pipe(
    // will send auth each 3s after connected
    // until it is authenticated or disconnected
    switchMap(() => timer(0, 3000).pipe(
      tap(() => console.log('Sending auth right after connect')),
      map(() => this._sendAuth()),
      // completing the status$ stream instead of switchMap
      takeUntil(auth$),
    )),
    map(() => {
      this._status = statusEnum.ON;
      return this._status;
    }),
  ),
  auth$.pipe(
    // this stream stop emitting if takeUntil is declared on connect$.
    map(() => {
      this._status = statusEnum.AUTHENTICATED;
      return this._status;
    })
  ),
);

编辑: 将共享运算符添加到要合并的auth管道后,合并的auth $再次开始产生价值。

const auth$ = this._response$.pipe(
  // this stream still emitting even if takeUntil is declared on connect$.
  filter(res => res.action === "authentication" && res.type === "success"),
  share(),
);

1 个答案:

答案 0 :(得分:1)

// assume a isConnect stream which return a boolean indicate connection status
let isConnect$ = new BehaviorSubject(false);

// assume a behavior subject to store a auth status
let isAuth$ = new BehaviorSubject(false);

disconnect$.subscribe(() => this.isConnect$.next(false));

connect$.subscribe(() => this.isConnect$.next(true));

// combine isConnect and isAuth together
let status$ = combineLatest(isConnect$, isAuth$).pipe(
  map(() => (isAuth ? statusEnum.AUTHENTICATED : isConnect ? statusEnum.ON : statusEnum.OFF)),
);

// a timer for sending auth every 3 secs and only send if status is statusEnum.ON;
let auth$ = timer(0, 3000)
  .pipe(
    switchMapTo(status$),
    filter(status => status === statusEnum.ON),
  )
  .subscribe(() => this.sendAuth());

// in this.sendAuth, after successfully get auth, you have to make isAuth$.next(true);