异步管道中的请求仅在前面的条件为真时触发
Request in async pipe is triggered only when preceding condition is true
我的模板中有一个 ngIf,类似于:
<div *ngIf="selectedStudents?.length > 0 && persistedPreferences | async as studentPreferences; else someTemplate">
代码目前部分是反应式的,部分是命令式的。我正在从命令式迁移到 declarative/reactive 范式。
selectedStudents
只是一个常规的对象数组,通过手动订阅从后端收到的响应来强制初始化(现在不能大量重构)。
但是,persistedPreferences
是一个可观察对象,它将从 http 请求(使用异步管道)获得响应。这部分是reactive/declarative.
因为 persistedPreferences
将被异步管道订阅,它的 http 请求只有在第一个条件为真时才会触发。这意味着我必须先等待收到 selectedStudents
响应,然后才会触发 persistedPreferences
请求。
因此,作为用户,我最终等待的时间稍长(在较慢的网络上)。
关于如何处理的任何想法?有什么提示吗?
注意:我们需要等待两个请求完成后用户才能看到任何内容。而且。来自两者的数据进入两个不同的组件。
我可以想到几个替代方案:
- 暂时将异步事物移到其他条件之前(不确定如何!)
- 也许稍微修改一下 - 使
selectedStudents
成为一个 observable 并将其与 persistedPreferences
组合成一个单独的 observable 并在模板中使用它?
像这样:
this.combinedObs = combineLatest([selectedStudentsObs, persistedPreferences]).pipe(
map(([res1, res2] => { students: res1, prefs: res2 }))
)
然后像这样使用它:
*ngIf="combinedObs | async as combinedResult"
<comp1 [students]="combinedResult.students"></comp1>
<comp2 [prefs]="combinedResult.prefs"></comp2>
但是第二种方式似乎不是一个很好的解决方案。考虑性能和错误处理。
被选中的学生才是真正重要的数据,一个http错误需要模糊的告知用户。首选项只是可选的东西(即使他们的 http 请求有一些错误,我们仍然可以显示选定的学生)。
第二种方式是优雅的方式,可以并行触发两个 HTTP 请求。但是,由于您提到两者都是 HTTP 请求,因此 forkJoin
比 combineLatest
更合适。
您可以处理错误,或在组件控制器中执行任何 side-effects。
控制器 (*.ts)
import { forkJoin, throwError } from 'rxjs';
import { tap, catchError } from 'rxjs/operators';
combineObs$: Observable<any>;
selectedStudents$: Observable<any>;
prefs$: Observable<any>;
this.selectedStudents$ = this.http.get('url').pipe(
tap((students: any) => { // performing side-effects
this.selectedStudents = students;
// do something else
}),
catchError((error: any) => {
// show error to the user
return throwError(error); // `catchError` must return an observable
})
);
this.prefs$ = this.http.get('url');
this.combinedObs$ = forkJoin({
students: this.selectedStudents$,
prefs: this.prefs$
});
模板(*.html)
<ng-container *ngIf="(combinedObs$ | async) as combinedResult">
<comp1 [students]="combinedResult.students"></comp1>
<comp2 [prefs]="combinedResult.prefs"></comp2>
</ng-container>
我的模板中有一个 ngIf,类似于:
<div *ngIf="selectedStudents?.length > 0 && persistedPreferences | async as studentPreferences; else someTemplate">
代码目前部分是反应式的,部分是命令式的。我正在从命令式迁移到 declarative/reactive 范式。
selectedStudents
只是一个常规的对象数组,通过手动订阅从后端收到的响应来强制初始化(现在不能大量重构)。
但是,persistedPreferences
是一个可观察对象,它将从 http 请求(使用异步管道)获得响应。这部分是reactive/declarative.
因为 persistedPreferences
将被异步管道订阅,它的 http 请求只有在第一个条件为真时才会触发。这意味着我必须先等待收到 selectedStudents
响应,然后才会触发 persistedPreferences
请求。
因此,作为用户,我最终等待的时间稍长(在较慢的网络上)。 关于如何处理的任何想法?有什么提示吗?
注意:我们需要等待两个请求完成后用户才能看到任何内容。而且。来自两者的数据进入两个不同的组件。
我可以想到几个替代方案:
- 暂时将异步事物移到其他条件之前(不确定如何!)
- 也许稍微修改一下 - 使
selectedStudents
成为一个 observable 并将其与persistedPreferences
组合成一个单独的 observable 并在模板中使用它?
像这样:
this.combinedObs = combineLatest([selectedStudentsObs, persistedPreferences]).pipe(
map(([res1, res2] => { students: res1, prefs: res2 }))
)
然后像这样使用它:
*ngIf="combinedObs | async as combinedResult"
<comp1 [students]="combinedResult.students"></comp1>
<comp2 [prefs]="combinedResult.prefs"></comp2>
但是第二种方式似乎不是一个很好的解决方案。考虑性能和错误处理。 被选中的学生才是真正重要的数据,一个http错误需要模糊的告知用户。首选项只是可选的东西(即使他们的 http 请求有一些错误,我们仍然可以显示选定的学生)。
第二种方式是优雅的方式,可以并行触发两个 HTTP 请求。但是,由于您提到两者都是 HTTP 请求,因此 forkJoin
比 combineLatest
更合适。
您可以处理错误,或在组件控制器中执行任何 side-effects。
控制器 (*.ts)
import { forkJoin, throwError } from 'rxjs';
import { tap, catchError } from 'rxjs/operators';
combineObs$: Observable<any>;
selectedStudents$: Observable<any>;
prefs$: Observable<any>;
this.selectedStudents$ = this.http.get('url').pipe(
tap((students: any) => { // performing side-effects
this.selectedStudents = students;
// do something else
}),
catchError((error: any) => {
// show error to the user
return throwError(error); // `catchError` must return an observable
})
);
this.prefs$ = this.http.get('url');
this.combinedObs$ = forkJoin({
students: this.selectedStudents$,
prefs: this.prefs$
});
模板(*.html)
<ng-container *ngIf="(combinedObs$ | async) as combinedResult">
<comp1 [students]="combinedResult.students"></comp1>
<comp2 [prefs]="combinedResult.prefs"></comp2>
</ng-container>