首页 > 解决方案 > rxjs 中最后一次发射的延迟

问题描述

我有一个Observable错误消息来源,我想为每个错误消息显示一个快餐栏。快餐栏出现DELAY毫秒,然后消失。

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

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

标签: rxjs

解决方案


由于您使用的是 Angular Material 的 Snackbar,因此您可以使用一个有用的方法.afterDismissed(),该方法返回一个可观察值,该 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. 我们的可观察管道进入主题并接收消息字符串。
  3. 在我们使用snackbar 之前,我们调用一个返回内部可观察对象的方法。(我们使用concatMap()它创建一个有序队列)
  4. 此方法创建我们的小吃店的引用变量。
  5. 如果小吃店是打开的,则返回一个可观察的,一旦它关闭就会发出消息。
  6. 如果snackbar 未打开,则返回一个立即发出消息的可观察对象。
  7. 回到我们的snackBar$observable,它接收到消息(或者立即,或者在小吃店关闭后)并触发小吃店。

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

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


推荐阅读