Angular 12/rxjs: как обрабатывать разветвление в отдельном методе

#angular #typescript #rxjs #fork-join

Вопрос:

Приведите следующий фрагмент кода, который выполняет следующее:

  1. сначала принесите списки
  2. затем, как только 1) будет закончен, вызовите initRouter()
 ngOnInit(): void {

   forkJoin([
      this.httpHandlerCached.getListsA(),
      this.httpHandlerCached.getListsB(),
      this.httpHandlerCached.getListsC()
   ]).subscribe(res => {
        this.listA = res[0];
        this.listB = res[1];
        this.listC = res[2];
        this.initRouter();
   })
}
 
initRouter(){
    this.route.params.subscribe(params =>
      //do something with params and lists...
}
 

Как я могу поместить первую соединительную часть в собственный метод, подобный этому:

 ngOnInit(): void {

   //Pseudo-Code:
   this.initListReturnForkJoin().subscribe(res => {
        this.listA = res[0];
        this.listB = res[1];
        this.listC = res[2];
        this.initRouter();
   })
}

//Pseudo-Code:
initListReturnForkJoin(): ??? {
   return forkJoin([
      this.httpHandlerCached.getListsA(),
      this.httpHandlerCached.getListsB(),
      this.httpHandlerCached.getListsC()
   ])
}
 
initRouter(){
    this.route.params.subscribe(params =>
      //do something with params and lists...
}
 

Извините, я не знаю, как лучше выразить этот вопрос… любое руководство приветствуется

Комментарии:

1. да, это выглядело бы именно так, как вы предлагали. тип возвращаемого значения будет Observable<[listAtype, listBtype,listCtype]>

2. Спасибо за это!!

Ответ №1:

Вложенные подписки, как правило, имеют запах кода. Вы можете использовать forkJoin снова или попробовать withLatestFrom (например), чтобы избежать вложенности подписок.

 ngOnInit(): void {

  this.route.params.pipe(
    // Update your lists every time the route emits
    withLatestFrom(this.fetchLists())
  ).subscribe(([params, listDict]) => {

    // Right here, both params and lists are defined
    this.doSomethingWithFetchedLists();

  });

}

// I don't know the types of your lists, 
// so I've put `any` as a placeholder for now.
fetchLists(): Observable<[any[],any[],any[]]> {

  return forkJoin({
    listA: this.httpHandlerCached.getListsA(),
    listB: this.httpHandlerCached.getListsB(),
    listC: this.httpHandlerCached.getListsC()
  }).pipe(
    tap(listDict => {
      // Update some global values as a side-effect of this
      // observable emitting. 
      this.listA = listDict.listA;
      this.listB = listDict.listB;
      this.listC = listDict.listC;
    })
  );
  
}