【问题标题】:Delay from last emission in rxjsrxjs 中最后一次发射的延迟
【发布时间】:2021-08-13 12:00:22
【问题描述】:

我有一个带有错误消息的源 Observable,我想为每个错误消息显示一个快餐栏。小吃栏出现DELAY ms,然后消失。

源可能是垃圾邮件值,因此下一条消息应该等到DELAY 毫秒后出现最后一条消息。如果这是第一条消息或自上一条消息以来已经过去了 DELAY 毫秒,则该消息应立即显示 (example source-result timings)。

我无法为此计算出正确的运算符组合。

【问题讨论】:

  • 你在使用 Angular Material 的 SnackBar 吗?
  • 是的,我正在使用 Material 小吃吧
  • 我最终使用了stackoverflow.com/a/55453545/15914746,但是一个干净的 rxjs 解决方案会很好

标签: rxjs


【解决方案1】:

由于您使用的是 Angular Material 的 Snackbar,因此您可以使用一个有用的方法 .afterDismissed(),它会返回一个 observable,该 observable 在小吃吧关闭时发出。

private emitError = new Subject<string>();
private snackBar$: Observable<string>;

constructor(private _snackBar: MatSnackBar) {
  this.snackBar$ = this.emitError
  .pipe(
    concatMap(message => this.getSnackBarDelay(message)),
    tap(message => this._snackBar.open(message, 'OK', { duration: 5000 }))
  );
}

public openSnackBar(message: string) {
  this.emitError.next(message);
}

private getSnackBarDelay(message: string) {
  const snackbarRef = this._snackBar._openedSnackBarRef;
  if (!!snackbarRef) {
    return snackbarRef!.afterDismissed().pipe(mapTo(message));
  } else {
    return of(message);
  }
}

这是正在发生的事情的分步过程。

  1. 我们的主题发出一条新的错误消息。
  2. 我们的 observable 管道进入主题并接收消息字符串。
  3. 在使用snackbar 之前,我们调用一个返回内部可观察对象的方法。 (我们使用concatMap(),所以它创建了一个有序队列)
  4. 此方法创建我们小吃店的引用变量。
  5. 如果小吃店已打开,则返回一个可在其关闭时发出消息的 observable。
  6. 如果快餐栏未打开,则返回一个可立即发出消息的可观察对象。
  7. 回到我们的snackBar$ observable,它会收到消息(立即,或者在关闭小吃店后)并触发小吃吧。

这样做的额外好处是,您不会尝试将计时器与小吃店应关闭的时间同步。即使用户提前点击关闭snackbar,也会立即触发下一个排队的错误。

这是一个工作原型的 Stackblitz:https://stackblitz.com/edit/angular-mwwcqb?file=src/app/snack-bar-component-example.ts

【讨论】:

    【解决方案2】:

    假设source$ 是发出错误消息的 Observable。

    您可以像这样将source$ 转换为满足您要求的新 Observable。评论是内联的。

    source$.pipe(
      // concatMap ensures that the notifications produced by the Observable
      // returned by the function passed as parameter are concatenated one after the other
      concatMap(i => {
        // the function 'of' transforms each notification of source$ into a new Observable which notifies
        // only once and then complete
        return of(i).pipe(
          // this tap simulates the fact that you open the Snackbar
          tap(msg => console.log('Open Snackbar for message', msg)),
          // introduce a delay between open and close
          delay(DELAY),
          // this tap simulates the fact that you close the Snackbar
          tap(msg => console.log('CLOSE Snackbar for message', msg)),
          // introduce a delay before the next error message is shown on the Snackbar
          // this delay represents the minimum delay, i.e. if the source$ does notify 
          // the next message only after this delay, this delay will have no effect
          delay(DELAY),
        )
      })
    ).subscribe()
    

    This stackbliz 模拟了你的情况,至少据我所知。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-13
      • 1970-01-01
      • 2019-05-23
      • 1970-01-01
      • 1970-01-01
      • 2018-07-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多