Firestore 监听器订阅触发随机次数

Firestore listener subscription triggers random number of times

我有一个 Firestore 侦听器似乎触发了随机次数。在第一个页面加载时,它可能会触发 5 次,刷新页面并触发 13 次。

@Injectable({
  providedIn: 'root',
})
export class AuthService {

  user$: BehaviorSubject<SavedUser | undefined> = new BehaviorSubject<SavedUser | undefined>(undefined);

  constructor(private angularFireAuth: AngularFireAuth, private firestore: AngularFirestore, private router: Router) {
    this.onAuthStateChanged();
  }

  onAuthStateChanged() {

    let counter = 0;

    this.angularFireAuth.authState.subscribe(user => {
      if (user) {
        this.firestore
          .collection('user')
          .doc<User>(user.uid)
          .valueChanges()
          .subscribe(userRecord => {
            counter++

            console.log(counter); // Testing

            user.getIdToken(true);

            this.user$.next(userRecord);
          });
      }
    });
  }
}

控制台日志的输出:

auth.service.ts:35 1
auth.service.ts:35 2
auth.service.ts:35 3
auth.service.ts:35 4
auth.service.ts:35 5
auth.service.ts:35 6
auth.service.ts:35 7
auth.service.ts:35 8
auth.service.ts:35 9
auth.service.ts:35 10
auth.service.ts:35 11

我在这里要做的就是在它支持的文档发生变化时刷新用户的令牌。

我知道 this.angularFireAuth.onAuthStateChanged(user => {...} 只触发了一次,文档没有发生任何变化。

我已经尝试通过 onDestroy 取消订阅 Firestore 订阅,但这没有任何区别。

作为“修复”,我认为我可以通过

读取第一个值并停止处理
this.firestore
  .collection('user')
  .doc<User>(user.uid)
  .valueChanges()
  .pipe(first())
  .subscribe(userRecord => {...});

乍一看确实有效,但是当稍后更改文档时,这会阻止 .valueChanges() 触发。

有什么建议吗?

好吧,我已经解决了我的实际问题,方法是通过另一个 firestore 侦听器在对象上设置时间戳,然后比较当前和上一个以仅触发一次。

如果有人来这里做类似的事情,我会post这个代码,但我仍然想知道为什么我的订阅者经常关闭。

云函数:

export class UserUpdateListener {

  public listen = functions.firestore
    .document('user/{uid}')
    .onWrite(async (snapshot) => {

      const before: User = snapshot.before.data() as User;
      const after: User = snapshot.after.data() as User;

      const skipUpdate = before.lastUpdate && after.lastUpdate && !before.lastUpdate.isEqual(after.lastUpdate);
      if (skipUpdate) {
        functions.logger.info('No changes, skipping timestamp update');
        return;
      }

      await snapshot.after.ref.update({ lastUpdate: admin.firestore.FieldValue.serverTimestamp() });
    });
}

然后我使用以下方法检查客户端中的时间戳:

constructor(private angularFireAuth: AngularFireAuth, private firestore: AngularFirestore, private router: Router) {
  this.onAuthStateChanged();

  let lastUpdate: Timestamp;

  this.user$.subscribe(async (user) => {
    if (this.authUser && user && user.lastUpdate) {
      if (lastUpdate && !user.lastUpdate.isEqual(lastUpdate)) {
        await this.authUser.getIdToken(true);
      }
      lastUpdate = user.lastUpdate;
    }
  });
}

希望这会节省一些时间。