Angular/RxJS - 延迟流直到上一个流完成
Angular/RxJS - Delay stream until previous stream finished
我正在构建一个应向用户显示通知的通知组件。当一次创建多个通知时,它应该将它们排队。
现在它显示第一个通知很好,但之后它同时触发了 2 个通知(请参阅下面的当前输出)。它不会等待上一个通知显示然后在显示下一个通知之前再次隐藏。
notifications.api.ts:
public notifications = new Subject<INotificationEvent>();
public notifications$ = this.notifications.asObservable();
notifications.component.ts:
private finished = new Subject();
constructor(private notifications: NotificationsApi) {}
zip(this.notificationsApi.notifications$, this.notificationsApi.notifications, (i, s) => s).pipe(
tap(() => {
if (!this.isActive) {
this.finished.next();
}
}),
delayWhen(() => this.finished),
delay(450),
tap((event: INotificationEvent) => {
this.notification = event;
this.isActive = true;
this.cd.markForCheck();
console.log(this.notification);
console.log('showing');
}),
delay(this.hideAfter),
tap(() => {
this.isActive = false;
this.cd.markForCheck();
console.log('closing');
}),
delay(450)
).subscribe(() => {
console.log('finishing');
this.finished.next();
});
app.component.ts:
let i = 0;
setInterval(() => {
this.notifications.newNotification({message: `${i}`, theme: 'primary'});
i++;
}, 2000);
当前输出:
{message: "0", theme: "primary"}
showing
closing
finishing
{message: "1", theme: "primary"}
showing
{message: "2", theme: "primary"}
showing
closing
finishing
{message: "3", theme: "primary"}
showing
{message: "4", theme: "primary"}
showing
closing
closing
finishing
finishing
{message: "5", theme: "primary"}
showing
{message: "6", theme: "primary"}
期望输出:
{message: "0", theme: "primary"}
showing
closing
finishing
{message: "1", theme: "primary"}
showing
closing
finishing
{message: "2", theme: "primary"}
showing
closing
finishing
{message: "3", theme: "primary"}
showing
closing
finishing
{message: "4", theme: "primary"}
showing
closing
finishing
{message: "5", theme: "primary"}
showing
closing
finishing
{message: "6", theme: "primary"}
showing
closing
finishing
我该如何解决这个问题?
根据您的描述,在我看来,您可以使用 concatMap
和 delay
轻松实现同样的目标。
在此示例中,每次单击按钮都代表一个通知。每个通知需要 2 秒。这取决于你想在观察者中做什么,但如果你根本不需要通知,你可以将它留空(否则你可能需要 startWith
)。多个通知在concatMap
里面排队,一个接一个执行。
const notification$ = fromEvent(document.getElementsByTagName('button')[0], 'click');
notification$.pipe(
concatMap(event => of(event).pipe(
tap(v => console.log('showing', v)),
delay(2000),
tap(v => console.log('closing', v)),
))
).subscribe();
我正在构建一个应向用户显示通知的通知组件。当一次创建多个通知时,它应该将它们排队。
现在它显示第一个通知很好,但之后它同时触发了 2 个通知(请参阅下面的当前输出)。它不会等待上一个通知显示然后在显示下一个通知之前再次隐藏。
notifications.api.ts:
public notifications = new Subject<INotificationEvent>();
public notifications$ = this.notifications.asObservable();
notifications.component.ts:
private finished = new Subject();
constructor(private notifications: NotificationsApi) {}
zip(this.notificationsApi.notifications$, this.notificationsApi.notifications, (i, s) => s).pipe(
tap(() => {
if (!this.isActive) {
this.finished.next();
}
}),
delayWhen(() => this.finished),
delay(450),
tap((event: INotificationEvent) => {
this.notification = event;
this.isActive = true;
this.cd.markForCheck();
console.log(this.notification);
console.log('showing');
}),
delay(this.hideAfter),
tap(() => {
this.isActive = false;
this.cd.markForCheck();
console.log('closing');
}),
delay(450)
).subscribe(() => {
console.log('finishing');
this.finished.next();
});
app.component.ts:
let i = 0;
setInterval(() => {
this.notifications.newNotification({message: `${i}`, theme: 'primary'});
i++;
}, 2000);
当前输出:
{message: "0", theme: "primary"}
showing
closing
finishing
{message: "1", theme: "primary"}
showing
{message: "2", theme: "primary"}
showing
closing
finishing
{message: "3", theme: "primary"}
showing
{message: "4", theme: "primary"}
showing
closing
closing
finishing
finishing
{message: "5", theme: "primary"}
showing
{message: "6", theme: "primary"}
期望输出:
{message: "0", theme: "primary"}
showing
closing
finishing
{message: "1", theme: "primary"}
showing
closing
finishing
{message: "2", theme: "primary"}
showing
closing
finishing
{message: "3", theme: "primary"}
showing
closing
finishing
{message: "4", theme: "primary"}
showing
closing
finishing
{message: "5", theme: "primary"}
showing
closing
finishing
{message: "6", theme: "primary"}
showing
closing
finishing
我该如何解决这个问题?
根据您的描述,在我看来,您可以使用 concatMap
和 delay
轻松实现同样的目标。
在此示例中,每次单击按钮都代表一个通知。每个通知需要 2 秒。这取决于你想在观察者中做什么,但如果你根本不需要通知,你可以将它留空(否则你可能需要 startWith
)。多个通知在concatMap
里面排队,一个接一个执行。
const notification$ = fromEvent(document.getElementsByTagName('button')[0], 'click');
notification$.pipe(
concatMap(event => of(event).pipe(
tap(v => console.log('showing', v)),
delay(2000),
tap(v => console.log('closing', v)),
))
).subscribe();