英文:
Angular APP_INITIALIZER Function Redirects Before List of Observables Completes
问题
我正在使用rxjs的from
函数将任何Observable<void>
成员的数组转换为单个可观察对象,然后将其传递给concatAll()
函数:
export const initApplication = (): (() => Observable<any>) => {
// 注入所有的服务
const initChain = [
jwtTokenService.init(),
myService1.init(),
myService2.init(),
....
appRouteService.init()
];
return () => from(initChain)
.pipe(
concatAll(),
);
}
不幸的是,应用程序的第一个操作发生在LandingComponent
中:
@Component({
selector: 'app-landing',
template: ''
})
export class LandingComponent implements OnInit {
constructor(private router : Router) { }
ngOnInit(): void {
this.router.navigate(['/home']);
}
}
尝试导航到/home的操作发生在APP_INITIALIZER函数中的Observables完成其任务之前(数组中的最后一个observable加载用户路由)。
from()
语法确保每个init()
函数等待前一个函数完成。但由于它不等待最后的Observable完成,因此会发生竞争条件。
有人可以告诉我如何确保重定向到/home发生在initApplication函数中的所有observables都完成之后?
(这是对这个问题的后续提问)。
英文:
I am using the rxjs from
function to convert any array of Observable<void>
members into a single observable which is piped to concatAll()
:
export const initApplication = (): (() => Observable<any>) => {
// inject() all services
const initChain = [
jwtTokenService.init(),
myService1.init(),
myService2.init(),
....
appRouteService.init()
];
return () => from(initChain)
.pipe(
concatAll(),
);
}
Unfortunately, the first action taken by the application occurs in LandingComponent
:
@Component({
selector: 'app-landing',
template: ''
})
export class LandingComponent implements OnInit {
constructor(private router : Router) { }
ngOnInit(): void {
this.router.navigate(['/home']);
}
}
The attempted navigation to /home occurs before the Observables in the APP_INITIALIZER function complete their tasks (the final observable in the array loads user routes).
The from()
syntax does ensure that each init()
function waits for the previous one to complete. But since it doesn't wait for the final Observable to complete, there's a race condition occuring.
Can anyone tell me how to make sure the redirect to /home doesn't occur until after all of the observables in the initApplication function are done?
(This is a followup to this question).
答案1
得分: 1
问题是由于使用了 concatAll 操作符引起的。一旦第一个内部 observable 发出,外部 observable 将会发出,并且初始化器将不再阻塞。最简单的解决方案是使用 forkJoin,它不会在所有 observables 完成之前发出。
export const initApplication = (): (() => Observable<any>) => {
const initChain = [
jwtTokenService.init(),
// ....
appRouteService.init()
];
return forkJoin(initChain);
}
如果您的意图真的是按顺序执行 init observables,那么您可以将 concat 操作符包装在 lastValueFrom 函数中。这将将 observable 转换为 promise,在最后一个 observable 发出时解析。Promise 是初始化器的有效返回类型。
export const initApplication = (): (() => Promise<any>) => {
const initChain = [/*...*/];
return lastValueFrom(concat(...initChain));
}
英文:
The issue is due to the use of the concatAll operator. Once the first inner observable emits, then the outer observable will emits and the initializer will no longer block. The easiest solution is to use forkJoin which won't emit until all observables complete.
export const initApplication = (): (() => Observable<any>) => {
const initChain = [
jwtTokenService.init(),
....
appRouteService.init()
];
return forkJoin(initChain);
}
If your intention is really to execute the init observables sequentially then you can wrap the concat operator inside lastValueFrom function. This converts the observable to a promise that resolves when the last observable emission occurs. A promise is a valid return type for an initializer.
export const initApplication = (): (() => Promise<any>) => {
const initChain = [/*...*/];
return lastValueFrom(concat(...initChain));
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论