Angular - 竞争条件 - 一次多个订阅
Posted
技术标签:
【中文标题】Angular - 竞争条件 - 一次多个订阅【英文标题】:Angular - race condition - multiple subscriptions at once 【发布时间】:2021-08-16 16:31:32 【问题描述】:我有一个UserService
,它有一个getUser
方法,该方法返回一个User
类的可观察对象。
getUser
检查用户是否已经存在,如果存在,则返回该用户,否则创建一个新用户。
当创建一个新用户时,它也会对用户的“角色”数据进行API调用,代码如下:
public getUser(): Observable<User>
if (!UserService.user)
UserService.user = new User();
return this.getGroups().pipe(
map(response =>
response.value.map(v => this.setRol(v));
return UserService.user;
));
else
return of(UserService.user);
但是有一个问题。
当我从两个不同的组件订阅此方法时,一个将遵循第一个 if 语句中的路径,第二个将返回 else 语句中创建的用户。
但第二个在第一个订阅完成 API 调用以获取用户所属的角色(组)之前返回创建的用户。这给了我错误。
我该如何解决这个问题?解决此问题的最佳做法是什么?
【问题讨论】:
UserService.user
可能是可观察的,您可以使用 last
这两个组件你想要什么?但这不是竞争条件,它可以正常工作,为什么我可以向您解释。
@ApoorvaChikara 在这两个组件中,我都需要用户并检查用户的角色。通过调用执行 http 调用的 getGroups 方法来扮演用户的角色。但我有一种感觉,我这样做完全错了..
【参考方案1】:
缓存shareReplay(1)
RxJS 让一种简单形式的缓存(像这样)变得非常容易
private userCache$ = this.getGroups().pipe(
map((value) =>
UserService.user = new User();
value.map(v => this.setRol(v));
return UserService.user;
),
shareReplay(1)
);
public getUser(): Observable<User>
return userCache$;
现在this.getGroups()
仅在第一次订阅userCache$
时才被调用。之后,所有其他调用都会等待 API 调用完成和/或获取该调用的缓存结果。
【讨论】:
【参考方案2】:我会在map
中设置UserService.user = new User();
来解决这个问题。
public getUser(): Observable<User>
if (!UserService.user)
// remove from here
// UserService.user = new User();
return this.getGroups().pipe(
map(response =>
// add here
UserService.user = new User();
response.value.map(v => this.setRol(v));
return UserService.user;
));
else
return of(UserService.user);
这样UsesrService.user
只会在API调用完成时设置。
【讨论】:
【参考方案3】:这里有很多选择,
最简单的方法是在 map
运算符中创建您的用户并改善条件。
public getUser(): Observable<User>
return !!UserService.user?.name // name or another property that we will help us understand that the user has initialized
? of(UserService.user)
: this.getGroups().pipe(
map(response =>
UserService.user = new User();
response.value.map(v => this.setRol(v));
return UserService.user;
));
PS:当你有if-else
条件时,通常建议先从true
部分开始。
【讨论】:
【参考方案4】:当你调用getUser
方法时,它首先检查UserService.user
的值,如果它不存在你调用API。但是,当您在两个components
中注入相同的服务时,它会调用此方法两次(我们知道这一点)。因此,当第二次调用它时,您将使用用户实例分配 UserService.user
,并且您的 else
将始终被调用。 observer
模式很好用,而且效果很好,angular 也推荐它。
public getUser(): Observable<User>
return new Observable(observer =>
if (!UserService.user.checkRolesExist())
UserService.user = new User();
return this.getGroups().pipe(
map(response =>
response.value.map(v => this.setRol(v));
observer.next(UserService.user);
observer.complete();
));
else
observer.next(UserService.user);
observer.complete();
);
现在,要检查用户是否存在,请在User
类上创建一个方法,该方法可以获取角色是否退出,这只是一个指导您的示例:
public checkRolesExist()
return UserService.user?.length > 0
【讨论】:
以上是关于Angular - 竞争条件 - 一次多个订阅的主要内容,如果未能解决你的问题,请参考以下文章
在 Angular 7 中,为啥即使只订阅一次 HttpClient.post 也会执行两次?
如何在 Angular 和 RxJs 中管理多个顺序订阅方法?
NgrxStore 和 Angular - 大量使用异步管道或在构造函数中只订阅一次