如何防止BehaviourSubject在定义之前被消耗? [英] How do you prevent a BehaviourSubject from being consumed before it's defined?
问题描述
我正在开发一种用户服务,该服务通过用户的user_id跟踪用户.它首先检查cookie中是否存在user_id,如果不是,它将向api发出get请求以创建一个新的id,并在响应中返回id.我的问题是,响应完成之前正在消耗user_id.我有两个问题:
I'm working on a user service that keeps track of users by their user_id. It first checks if user_id is present in their cookies, if it isn't it makes a get request to the api to create a new one and returns the id in the response. My problem is that the user_id is being consumed before the response is completed. I have two questions:
- BehaviourSubject甚至在被定义为新的BehaviourService之前就已被使用,使用它的组件正在
undefined
上调用.subscribe(),结果该应用程序崩溃了. - 我每次要检索user_id时真的需要订阅吗?由于我先订阅了behavioursubject,然后在subscribe方法中订阅了代码,因此代码变得难以工作.我想不出一种更好的方法来解决这个问题,从我读过的文章中,他们提到链接流是正确的方法,但这感觉很不对.
- The BehaviourSubject is being consumed before it's even defined as a new BehaviourService, components that consume it are calling .subscribe() on
undefined
as a result and the app is crashing. - Is the really necessary for me to subscribe to the user_id every single time I want to retrieve it? The code is turning into hell to work with since i'm subscribing to the behavioursubject first and then inside the subscribe method I'm writing my code. I can't figure out a better way to go about it, and from the texts I've read they mention that linking streams is the right approach, but this just feels very wrong.
这是我在做什么的简化示例
Here's a simplified example of what I'm doing
constructor(...) {
public ruid: BehaviorSubject<any>;
if(!Cookies.get('ruid')) {
this.http.get(url).subscribe(
(value) => {
this.ruid = new BehaviorSubject(value)
Cookies.set('ruid', value)
}
)
} else {
this.ruid = new BehaviorSubject(Cookie.get('ruid'));
}
}
在组件中使用常规
constructor(private userService: UserService) {
data;
this.userService.ruid.subscribe(
(value) => {
this.data = this.http.get(url + value).map(res => res.json())
}
);
}
推荐答案
我相信您需要在此处设置路由解析器.在下面的真实项目中查看我的示例:
I believe what you need here is to setup resolver on your route. See my example from real project below:
resolver.ts
@Injectable()
export class LocationResolver implements Resolve<any> {
constructor(private locationsApiService: LocationsApiService, private appStorage: AppStorage, private authService: AuthService) {
}
resolve(route: ActivatedRouteSnapshot): Observable<any> {
return new Observable((observer) => {
const sessionData = this.authService.getSessionData();
if (!sessionData.Location) {
this.locationsApiService.getUserLocations().subscribe(
locations => {
sessionData.Location = locations[0].Name;
sessionData.LocationId = locations[0].Id;
this.authService.updateSessionData(sessionData);
this.appStorage.set(AppConstants.storage.userLocations, locations);
observer.next(sessionData.LocationId);
observer.complete();
}
);
} else {
observer.next(sessionData.LocationId);
observer.complete();
}
});
}
}
路线
{
path: 'app',
component: MainComponent,
canActivate: [AuthGuard],
resolve: {
locationId: LocationResolver
},
children: [...]
}
基本上,它没有解决路由问题,直到获得必要的数据为止.就我而言,我需要查询locationId并将其提供给登录后的每个呼叫.因此,解析程序要么在LocalStorage中寻找它,要么对API进行调用,然后设置位置.
Basically what it does is not resolving route up until it gets the necessary data. In my case I need to query locationId and provide it to every call after login. So resolver either looks for it in LocalStorage or doing a call to the API and then sets the location.
UPD:根据您的情况,您可以将此类解析器放在预订BehaviorSubject的路由上,直到您完成所有API调用后,它才会被实例化和预订.
UPD: In your case you can put such resolver on the route that subscribes to BehaviorSubject and it will not get instantiated and subscribed until you finish all the API calls.
这篇关于如何防止BehaviourSubject在定义之前被消耗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!