首页 > 解决方案 > 为什么switchMap中的间隔停止发射值

问题描述

我想使用 rxjs 在我的应用程序中轮询用户会话,但仅在用户会话处于活动状态时。

我将用户会话存储在会话存储中。当我们打开应用程序时,它是空的,当我们登录时它会被刷新,并且它所附加的 BehaviourSubject 也会被更新。然后我开始一个 rxjs 间隔,直到会话过期,这样我就可以调用注销。

sessionUser$ = new BehaviorSubject<UserAuthSession>(this.getSessionUser());

private pollSessionTimeout(): void {
    this.sessionUser$
      .pipe(
        filter(user => {
          return user !== null;
        }),
        switchMap(() => interval(1000)),
        skipWhile(this.isAuthenticated),
        take(1)
      )
      .subscribe(x => {
        console.log('Poll is deleting session', x);
        this.deleteSession();
        this.router.navigate(['auth/login']);
      });
}

我希望当我们第一次启动应用程序并且没有用户时,间隔不会运行。这是有效的!

我希望在我们登录后,发送一个新的非空 sessionUser 事件,我们开始间隔,直到 isAuthenticated (检查会话是否过期)为假,然后只使用 1 个事件注销。这是有效的!

我希望如果我手动注销,则会发送一个新的空 sessionUser 事件来停止间隔。这不起作用,因为它仍然通过一次 isAuthenticated 并再次调用 delete 。不理想,但我可以解决它。更大的问题是当我再次登录时,间隔只运行 4 次(为什么?)然后停止运行并检查是否 isAuthenticated。

知道为什么会这样吗?你建议另一种方法吗?

标签: javascriptangularrxjs

解决方案


我不完全确定你想要的逻辑,但似乎你可以重组你已经拥有的链。然后,如果你想interval停止发射,你可以EMPTYswitchMap.

import { EMPTY } from 'rxjs';
...

this.sessionUser$
  .pipe(
    switchMap(user => {
      if (user) {
        return interval(1000).pipe(
          skipWhile(this.isAuthenticated),
          take(1)
        );
      } else {
        return EMPTY;
      }
    })
  ).subscribe(...);

推荐阅读