有人可以解释为什么 BehaviorSubject 结果是这样的吗?
Can someone explain that why the BehaviorSubject result like this?
我编写了一个服务,其中包含一个名为 loginStatus 的 BehaviorSubject 和一个 return 函数。
private loginStatus = new BehaviorSubject<boolean>(false);
getLoginStatus(): Observable<boolean> {
return this.loginStatus;
}
然后我在其他组件的 DOM 中使用 4 个不同 div 中的异步管道订阅它,我只是评论了 shareReplay 以显示我的疑惑。
loginStatus$ = this.authService.getLoginStatus().pipe(
switchMap(res => {
if (!res) { return this.authService.isLoggedIn(); }
else { return of(res); }
}),
tap(res => console.log('tap: ' + res)),
//shareReplay(1),
);
isLoggedIn 是一个 http 请求,用于检查我是否登录,我检查 switchMap 中的 loginStatus 值,如果为假,则调用 isLoggedIn
isLoggedIn(): Observable<boolean> {
console.log('called isLoggedIn');
return this.httpService.get('/auth/isLoggined').pipe(
map(res => {
console.log('isLoggedIn res: ' + JSON.stringify(res));
if (res) {
this.loginStatus.next(true);
this.firstName = res.first_name;
this.lastName = res.last_name;
this.tel = res.tel;
return 'fool';
} else {
this.clearAll();
return false;
}
}),
最后是我的控制台结果:
called isLoggedIn
called isLoggedIn
called isLoggedIn
called isLoggedIn
isLoggedIn 被调用了 4 次,因为我的 4 个异步管道,并且 loginStatus 为 false。
当第一个 http 请求响应时,我得到了一个 json 对象,如 {first_name:xxx, last_name:yyy, 1234},所以我将 true 推送到 loginStatus 和 return a 'fool' 给进一步的操作员。
我想我会在 loginStatus$ 的 tap 运算符中得到傻瓜,但事实并非如此。
isLogedIn res: {"logined":true,"first_name":"xxx","last_name":"yyy","tel":"1234"}
tap: true
tap: true
tap: true
tap: true
我只得到了第一个 isLoggedIn 请求的响应,其他 3 个都丢失了。
而且我从来没有得到傻瓜,我猜所有的异步管道都从 loginStatus BehaviorSubject 得到 true。
然后我在isLoggedIn函数中注释了this.loginStatus.next(true)来比较结果
isLogedIn res: {"logined":true,"first_name":"xxx","last_name":"yyy","tel":"1234"}
tap: fool
isLogedIn res: {"logined":true,"first_name":"xxx","last_name":"yyy","tel":"1234"}
tap: fool
isLogedIn res: {"logined":true,"first_name":"xxx","last_name":"yyy","tel":"1234"}
tap: fool
isLogedIn res: {"logined":true,"first_name":"xxx","last_name":"yyy","tel":"1234"}
tap: fool
这是我喜欢的结果,我打了 4 次电话,所以我得到了 4 次回应,它把傻瓜传给了水龙头 4 次。
我想知道为什么我在第一次订阅的过程中更改了BehaviorSubject时,另一个reponse丢失了。
以及为什么所有 4 个订阅都获得真实值,我想至少第一次会得到傻瓜。
这是否意味着 BehaviorSubject 将在更改时取消进一步的过程而不是完成它?
请试试这个
private loginStatus = new BehaviorSubject<boolean>(false);
getLoginStatus(): Observable<boolean> {
return this.loginStatus.asObservable();
}
this.loginStatus$ = this.getLoginStatus().pipe(
mergeMap((res) => {
if (!res) {
return this.isLoggedIn();
} else {
return of(res);
}
}),
tap(res => console.log('tap: ' + res)),
);
}
这给出了预期的 4 个结果。
发生这种情况是因为 switchMap 运算符。
当你调用 this.loginStatus.next(true);
时,它会切换到最新事件,并从 this.loginStatus$
可观察到并在 else 内部执行语句,并在 tap true 中打印时间。
如果您设置 this.loginStatus.next(false);
这将设置为无限循环。
结论
如果你输入任意数量的 loginStatus$ | async
因为你正在使用 switchMap
,内部 observable 将被调用一次。
switchMap
之后的 tap
管道将根据 | async
管道订阅数调用。
发生这种情况是因为您正在使用 switchMap
,这将取消之前的内部可观察对象并处理新的。
因此,当您使用 this.loginStatus.next(true)
在 BehaviorSubject
中发出一个值时,switchMap
运算符将取消先前的可观察值并处理新值(为真)。
如果你想实现你的场景,你应该保持之前的内部观察正常完成,那么你需要使用mergeMap
或concatMap
运算符。
我编写了一个服务,其中包含一个名为 loginStatus 的 BehaviorSubject 和一个 return 函数。
private loginStatus = new BehaviorSubject<boolean>(false);
getLoginStatus(): Observable<boolean> {
return this.loginStatus;
}
然后我在其他组件的 DOM 中使用 4 个不同 div 中的异步管道订阅它,我只是评论了 shareReplay 以显示我的疑惑。
loginStatus$ = this.authService.getLoginStatus().pipe(
switchMap(res => {
if (!res) { return this.authService.isLoggedIn(); }
else { return of(res); }
}),
tap(res => console.log('tap: ' + res)),
//shareReplay(1),
);
isLoggedIn 是一个 http 请求,用于检查我是否登录,我检查 switchMap 中的 loginStatus 值,如果为假,则调用 isLoggedIn
isLoggedIn(): Observable<boolean> {
console.log('called isLoggedIn');
return this.httpService.get('/auth/isLoggined').pipe(
map(res => {
console.log('isLoggedIn res: ' + JSON.stringify(res));
if (res) {
this.loginStatus.next(true);
this.firstName = res.first_name;
this.lastName = res.last_name;
this.tel = res.tel;
return 'fool';
} else {
this.clearAll();
return false;
}
}),
最后是我的控制台结果:
called isLoggedIn
called isLoggedIn
called isLoggedIn
called isLoggedIn
isLoggedIn 被调用了 4 次,因为我的 4 个异步管道,并且 loginStatus 为 false。
当第一个 http 请求响应时,我得到了一个 json 对象,如 {first_name:xxx, last_name:yyy, 1234},所以我将 true 推送到 loginStatus 和 return a 'fool' 给进一步的操作员。
我想我会在 loginStatus$ 的 tap 运算符中得到傻瓜,但事实并非如此。
isLogedIn res: {"logined":true,"first_name":"xxx","last_name":"yyy","tel":"1234"}
tap: true
tap: true
tap: true
tap: true
我只得到了第一个 isLoggedIn 请求的响应,其他 3 个都丢失了。 而且我从来没有得到傻瓜,我猜所有的异步管道都从 loginStatus BehaviorSubject 得到 true。
然后我在isLoggedIn函数中注释了this.loginStatus.next(true)来比较结果
isLogedIn res: {"logined":true,"first_name":"xxx","last_name":"yyy","tel":"1234"}
tap: fool
isLogedIn res: {"logined":true,"first_name":"xxx","last_name":"yyy","tel":"1234"}
tap: fool
isLogedIn res: {"logined":true,"first_name":"xxx","last_name":"yyy","tel":"1234"}
tap: fool
isLogedIn res: {"logined":true,"first_name":"xxx","last_name":"yyy","tel":"1234"}
tap: fool
这是我喜欢的结果,我打了 4 次电话,所以我得到了 4 次回应,它把傻瓜传给了水龙头 4 次。
我想知道为什么我在第一次订阅的过程中更改了BehaviorSubject时,另一个reponse丢失了。
以及为什么所有 4 个订阅都获得真实值,我想至少第一次会得到傻瓜。
这是否意味着 BehaviorSubject 将在更改时取消进一步的过程而不是完成它?
请试试这个
private loginStatus = new BehaviorSubject<boolean>(false);
getLoginStatus(): Observable<boolean> {
return this.loginStatus.asObservable();
}
this.loginStatus$ = this.getLoginStatus().pipe(
mergeMap((res) => {
if (!res) {
return this.isLoggedIn();
} else {
return of(res);
}
}),
tap(res => console.log('tap: ' + res)),
);
}
这给出了预期的 4 个结果。
发生这种情况是因为 switchMap 运算符。
当你调用 this.loginStatus.next(true);
时,它会切换到最新事件,并从 this.loginStatus$
可观察到并在 else 内部执行语句,并在 tap true 中打印时间。
如果您设置 this.loginStatus.next(false);
这将设置为无限循环。
结论
如果你输入任意数量的 loginStatus$ | async
因为你正在使用 switchMap
,内部 observable 将被调用一次。
switchMap
之后的 tap
管道将根据 | async
管道订阅数调用。
发生这种情况是因为您正在使用 switchMap
,这将取消之前的内部可观察对象并处理新的。
因此,当您使用 this.loginStatus.next(true)
在 BehaviorSubject
中发出一个值时,switchMap
运算符将取消先前的可观察值并处理新值(为真)。
如果你想实现你的场景,你应该保持之前的内部观察正常完成,那么你需要使用mergeMap
或concatMap
运算符。