使用 rxjs concat 多次调用 AuthorizeService isAuthenticated() 订阅
AuthorizeService isAuthenticated() subscribe being called multiple times with rxjs concat
我正在使用来自 visual studio 模板的默认客户端身份验证服务。
有一个打字稿 AuthorizeService,它有一个名为 isAuthenticated 的函数,它调用下面的函数并检查它是否为 null。
getUser 函数:
public getUser(): Observable<IUser> {
return concat(
this.userSubject.pipe(take(1), filter(u => !!u)),
this.getUserFromStorage().pipe(filter(u => !!u), tap(u => this.userSubject.next(u))),
this.userSubject.asObservable());
}
在上述函数上调用 .subscribe 时。订阅被调用了三次。大概是针对 concat 函数中的每个可观察对象。使用上面的 getUser,我希望订阅被调用一次。我将如何实现?
我尝试将上面的内容转换为 returns 一个值的嵌套承诺,但由于某种原因没有成功,返回结果后,它 returns resolve(null) 即使用户存在于会话存储中
考虑改用 forkJoin
(当所有 observable 完成时,将每个 observable 的最后一个发射值作为数组发出),如下所示:
注意:我已将 take
运算符添加到最后一个可观察对象,以便它完成
public getUser(): Observable <[IUser, IUser, IUser]> {
return forkJoin(
this.userSubject.pipe(take(1), filter(u => !!u)),
this.getUserFromStorage().pipe(filter(u => !!u), tap(u => this.userSubject.next(u))),
this.userSubject.asObservable().pipe(take(1))
);
}
我假设您只希望 getUser() return 一个用户。现在,您的逻辑是“获取 userSubject 的当前值并从存储中获取用户,还获取 userSubject 的当前值和所有未来值。”
这意味着如果 userSubject 的值为 truthy,您将至少返回 3 个用户。这就是你的逻辑。
我不确定你所说的 'only subscribe once,' 是什么意思,但我假设你的意思是 'only return 1 user.' 一种简单的方法是只从你的 concat 调用中获取一个值:
return concat(...).pipe(take(1));
这可能会导致不可预知的行为。三个流中的任何一个首先发出一个值将是您获取的值。如果 getUserFromStorage() 需要一些时间才能完成,您将始终返回 null。我猜这就是你在嵌套承诺时发生的事情(尽管我必须查看你的代码才能确定)。
更好的方法是使用 switchMap 或 mergeMap(在这种情况下都可以)我还猜测如果 userSubject 中没有用户,您只想从后端获取用户。这种方法将有效地缓存当前经过身份验证的用户。
public getUser(): Observable<IUser> {
return this.userSubject.pipe(
take(1),
mergeMap(u => {
if(u) return of(u);
return this.getUserFromStorage().pipe(
tap(u => u && this.userSubject.next(u))
);
}),
take(1)
);
}
这是做什么的?仅当来自 userSubject 的用户不真实时,它才会尝试从存储中获取用户。如果 userSubject 中有用户,则永远不会调用(或订阅)this.getUserFromStorage()。值得注意的是,如果 getUserFromStorage() 仅 return 一个值,则不需要第二次调用 take(1) 。这还假设如果存储中没有用户,getUserFromStorage() returns null。
最后,我删除了所有过滤器,因为(根据您的描述)您希望此流 return 如果主题中没有用户且存储中没有用户则为 null。如果我们过滤掉 null return 那么我们将永远不会 return null。相反,我所做的是,如果 getUserFromStorage() returns null.
我们只 return null
我正在使用来自 visual studio 模板的默认客户端身份验证服务。
有一个打字稿 AuthorizeService,它有一个名为 isAuthenticated 的函数,它调用下面的函数并检查它是否为 null。
getUser 函数:
public getUser(): Observable<IUser> {
return concat(
this.userSubject.pipe(take(1), filter(u => !!u)),
this.getUserFromStorage().pipe(filter(u => !!u), tap(u => this.userSubject.next(u))),
this.userSubject.asObservable());
}
在上述函数上调用 .subscribe 时。订阅被调用了三次。大概是针对 concat 函数中的每个可观察对象。使用上面的 getUser,我希望订阅被调用一次。我将如何实现?
我尝试将上面的内容转换为 returns 一个值的嵌套承诺,但由于某种原因没有成功,返回结果后,它 returns resolve(null) 即使用户存在于会话存储中
考虑改用 forkJoin
(当所有 observable 完成时,将每个 observable 的最后一个发射值作为数组发出),如下所示:
注意:我已将 take
运算符添加到最后一个可观察对象,以便它完成
public getUser(): Observable <[IUser, IUser, IUser]> {
return forkJoin(
this.userSubject.pipe(take(1), filter(u => !!u)),
this.getUserFromStorage().pipe(filter(u => !!u), tap(u => this.userSubject.next(u))),
this.userSubject.asObservable().pipe(take(1))
);
}
我假设您只希望 getUser() return 一个用户。现在,您的逻辑是“获取 userSubject 的当前值并从存储中获取用户,还获取 userSubject 的当前值和所有未来值。”
这意味着如果 userSubject 的值为 truthy,您将至少返回 3 个用户。这就是你的逻辑。
我不确定你所说的 'only subscribe once,' 是什么意思,但我假设你的意思是 'only return 1 user.' 一种简单的方法是只从你的 concat 调用中获取一个值:
return concat(...).pipe(take(1));
这可能会导致不可预知的行为。三个流中的任何一个首先发出一个值将是您获取的值。如果 getUserFromStorage() 需要一些时间才能完成,您将始终返回 null。我猜这就是你在嵌套承诺时发生的事情(尽管我必须查看你的代码才能确定)。
更好的方法是使用 switchMap 或 mergeMap(在这种情况下都可以)我还猜测如果 userSubject 中没有用户,您只想从后端获取用户。这种方法将有效地缓存当前经过身份验证的用户。
public getUser(): Observable<IUser> {
return this.userSubject.pipe(
take(1),
mergeMap(u => {
if(u) return of(u);
return this.getUserFromStorage().pipe(
tap(u => u && this.userSubject.next(u))
);
}),
take(1)
);
}
这是做什么的?仅当来自 userSubject 的用户不真实时,它才会尝试从存储中获取用户。如果 userSubject 中有用户,则永远不会调用(或订阅)this.getUserFromStorage()。值得注意的是,如果 getUserFromStorage() 仅 return 一个值,则不需要第二次调用 take(1) 。这还假设如果存储中没有用户,getUserFromStorage() returns null。
最后,我删除了所有过滤器,因为(根据您的描述)您希望此流 return 如果主题中没有用户且存储中没有用户则为 null。如果我们过滤掉 null return 那么我们将永远不会 return null。相反,我所做的是,如果 getUserFromStorage() returns null.
我们只 return null