【问题标题】:Angular 7 nested observablesAngular 7 嵌套的 observables
【发布时间】:2019-08-04 01:01:08
【问题描述】:

我有两个系列:人物和宠物。每个宠物都有personId。我的目标是让所有人和他们中的每个人都将他/她的宠物添加到单个 json 中。到目前为止我所做的是:

this.personService.getPersions().subscribe(persons => {
  const personsWithPets = persons.flatMap(person => this.petService.getPetsByPersonId(person._id)
    .subscribe(petsData => {
      person.pets = petsData;
      return person;
    }, (err) => {
     console.log(err);
    }));
  this.persons = personsWithPets; // This is fired before previous subscribe
}, (err) => {
  console.log(err);
});

我做错了什么?为什么this.persons = personsWithPets; 在订阅完成之前被触发?

【问题讨论】:

  • 因为您的getPetsByPersonId 可能是异步的,因此您对getPetsByPersonId().subscribe 的调用中的代码可能要到this.persons = personsWithPets 之后才会返回值。 subscribe 被调用,只是里面的代码在服务返回值之前不会运行。它确实与嵌套的 observables 无关
  • 有什么建议可以让它工作吗?

标签: javascript angular observable subscription angular2-observables


【解决方案1】:

更新添加了 cmets

另一个:stackblitz

this.service.getPersons().pipe(switchMap((per:any[])=>{
       //create an array of observables
       const obs=per.map(per=>this.service.getPet(per.id));
       //call all of them in forkjoin
       return forkJoin(obs).pipe(map(pets=>
         //pets is an array, in pets[0] is the response of getPet(1), 
         //in pets[1] is the response of getPet(2)
         pets.map((pet,i)=>{
           return {
             ...per[i], //all the properties of the person
             pets:pet   //+ in pets an array with the pets of the person
             }
         })
       ))
     })).subscribe(res=>this.res=res)

【讨论】:

    【解决方案2】:

    Observable 本质上是异步的。订阅调用将在另一个线程中运行,而方法中的其余指令将继续在主线程中运行。您需要做的是等到异步操作完成后再运行下一个操作。您可以通过将非指令放在订阅中来做到这一点,或者更好的是使用 (err) 参数之后的 onCompleted 参数,就像这样

    this.personService.getPersons().subscribe(persons => {
      const personsWithPets = persons.flatMap(person => 
            this.petService.getPetsByPersonId(person._id)
                .subscribe(petsData => {
                     person.pets = petsData;
                     return person;
                 }, 
                 (err) => {
                     console.log(err);
                 },
                 () => {
                     this.persons = personsWithPets;
                 }))
            });
    

    【讨论】:

      【解决方案3】:

      我给你做了个例子

      const { of } = rxjs;
      const { map, switchMap, toArray, mergeMap } = rxjs.operators;
      
      function getPeople() {
        return of([{ id: 1, name: 'Amanda' }, { id: 2, name: 'Nancy' }]);
      }
      
      function getPetsByPersonId(id) {
        switch(id) {
          case 1:
            return of(['Doggie']);
          case 2:
            return of(['Kitten']);
        }
      }
      
      const getPets = (person) => {
        return getPetsByPersonId(person.id).pipe(
          map(pets => ({ ...person, pets }))
        )
      }
      
      getPeople().pipe(
        switchMap(people => people),
        mergeMap(getPets),
        toArray()
      )
        .subscribe(peopleWithPets => console.log(peopleWithPets));
      <script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>

      【讨论】:

      • 订阅类型上不存在管道
      • 哪个管道? getPetsByPersonId 或 getPeople?能否请您发布这些功能代码?
      • 现在我得到了 TypeError: this.getPetsByPersonId is not a function
      【解决方案4】:

      在 subscribe 中使用 subscribe 被认为是一种不好的做法,并且可能会导致您所描述的问题。我建议将 mergeMap 与 forkJoin 运算符结合使用:

      this.personService.getPersions().pipe(mergeMap(persons => {
         const requests = persons.map(person => this.petService.getPetsByPersonId(person._id));
         return forkJoin(of(persons), ...requests);
      }),
      map(values => {
        const persons = values[0];
        const pets = values.slice(1);
        // here you need to assign correct pet to correct person
      
      })
      ).subscribe(personsWithPets => {
        console.log(personsWithPets);
      }, err => {
        console.log(err);
      });

      【讨论】:

      • 这张 map(values => { 返回正确的宠物数组,但是如何结合 person 和 values[nth]?
      猜你喜欢
      • 2019-10-27
      • 2017-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-25
      • 2019-08-15
      • 2018-12-20
      相关资源
      最近更新 更多