Angular APP_INITIALIZER 函数在观察列表完成之前重定向。

huangapple go评论68阅读模式
英文:

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 = (): (() =&gt; Observable&lt;any&gt;) =&gt; {
  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 = (): (() =&gt; Promise&lt;any&gt;) =&gt; {
  const initChain = [/*...*/];
  return lastValueFrom(concat(...initChain));
}

huangapple
  • 本文由 发表于 2023年6月8日 01:32:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76425788.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定