Angular RESTAPI上的多个HTTP请求

Angular RESTAPI上的多个HTTP请求,angular,typescript,ionic-framework,Angular,Typescript,Ionic Framework,我编写了一个函数,该函数从pokeapi.co获取pokemon的可观察列表。如果我想使用这个函数(getPokemons()),我需要订阅它。但是,subscribe响应返回一个空列表,因为在我的函数中,我使用subscribe函数执行另一个API调用 互联网澄清了在http请求中订阅是一个常见的错误,您需要使用forkMap、flatMap、switchMap、mergeMap或其他任何东西。不幸的是,我不明白如何将这些函数之一应用到我的案例中 getPokemons(pageNumber:

我编写了一个函数,该函数从pokeapi.co获取pokemon的可观察列表。如果我想使用这个函数(getPokemons()),我需要订阅它。但是,subscribe响应返回一个空列表,因为在我的函数中,我使用subscribe函数执行另一个API调用

互联网澄清了在http请求中订阅是一个常见的错误,您需要使用forkMap、flatMap、switchMap、mergeMap或其他任何东西。不幸的是,我不明白如何将这些函数之一应用到我的案例中

getPokemons(pageNumber: number) : Observable<Pokemon[]> {
    var apiUrl = `${this.apiRoot}?&limit=${this.itemCount}&offset=${pageNumber * this.itemCount - (20)}`;
    return this.httpClient.get<any>(`${apiUrl}`).pipe(
      map(res => {
        var results: Pokemon[] = [];
        for (let pokemon of res.results) {
          this.getPokemonByName(pokemon.name).subscribe(data => {
            results.push(data);
          },
          err =>  {
            console.error(err.error || 'API error');
          });
        }
        return results;
      })
    );
  }

getPokemonByName(name: string) : Observable<Pokemon> {
    return this.httpClient.get<Pokemon>(`${this.apiRoot}/${name}`).pipe(
      map(res => {
        return new Pokemon(res);
      })
    );
  }
getPokemons(页码:number):可观察{
var apirl=`${this.apiRoot}?&limit=${this.itemCount}&offset=${pageNumber*this.itemCount-(20)}`;
返回此.httpClient.get(`${apirl}`).pipe(
地图(res=>{
风险值结果:口袋妖怪[]=[];
对于(让口袋妖怪的结果){
this.getPokemonByName(pokemon.name).subscribe(数据=>{
结果:推送(数据);
},
错误=>{
console.error(err.error | | |“API错误”);
});
}
返回结果;
})
);
}
getPokemonByName(名称:string):可观察{
返回此.httpClient.get(`${this.apiRoot}/${name}').pipe(
地图(res=>{
归还新口袋妖怪(res);
})
);
}
在我的场景中,原始的http.get()响应一个只有口袋妖怪名称的列表。我需要做另一个API调用来获取特定口袋妖怪的详细信息。因为getPokemonByName().subscribe()是异步的,所以数组“results”保持为空


我希望你能理解我的问题,你能帮我找到解决办法

您确实可以使用RxJS操作符简化
getPokemons()
方法,例如
forkJoin()
将在返回所有可观测值之前完成
for..of
循环。如果您熟悉JavaScript中承诺的用法,它实际上类似于
Promise.all

一旦您订阅了它,您将能够获得返回值。不要忘记将所需的运算符导入组件中

import { forkJoin } from 'rxjs';
.
.
getPokemons(pageNumber: number): Observable < Pokemon[] > {
  const apiUrl = `${this.apiRoot}?&limit=${this.itemCount}&offset=${pageNumber * this.itemCount - (20)}`;
  const observablesList = [];

  return this.httpClient.get<any>(`${apiUrl}`).pipe(
    map(res => {
      const observablesList = [];
      for (let pokemon of res.results) {
        observablesList.push(this.getPokemonByName(pokemon.name));
      }
      return forkJoin(observablesList);
    })
  ).subscribe(res => {
    console.log(res);
    // do the rest here
  })
}
从'rxjs'导入{forkJoin};
.
.
getPokemons(页码:number):可观察{
const apirl=`this.apiRoot}?&limit=${this.itemCount}&offset=${pageNumber*this.itemCount-(20)}`;
常量observesList=[];
返回此.httpClient.get(`${apirl}`).pipe(
地图(res=>{
常量observesList=[];
对于(让口袋妖怪的结果){
push(this.getPokemonByName(pokemon.name));
}
返回forkJoin(observablesList);
})
).订阅(res=>{
控制台日志(res);
//其余的在这里做
})
}

您确实可以使用RxJS操作符简化
getPokemons()
方法,例如
forkJoin()
将在返回所有可观测值之前完成
for..of
循环。如果您熟悉JavaScript中承诺的用法,它实际上类似于
Promise.all

一旦您订阅了它,您将能够获得返回值。不要忘记将所需的运算符导入组件中

import { forkJoin } from 'rxjs';
.
.
getPokemons(pageNumber: number): Observable < Pokemon[] > {
  const apiUrl = `${this.apiRoot}?&limit=${this.itemCount}&offset=${pageNumber * this.itemCount - (20)}`;
  const observablesList = [];

  return this.httpClient.get<any>(`${apiUrl}`).pipe(
    map(res => {
      const observablesList = [];
      for (let pokemon of res.results) {
        observablesList.push(this.getPokemonByName(pokemon.name));
      }
      return forkJoin(observablesList);
    })
  ).subscribe(res => {
    console.log(res);
    // do the rest here
  })
}
从'rxjs'导入{forkJoin};
.
.
getPokemons(页码:number):可观察{
const apirl=`this.apiRoot}?&limit=${this.itemCount}&offset=${pageNumber*this.itemCount-(20)}`;
常量observesList=[];
返回此.httpClient.get(`${apirl}`).pipe(
地图(res=>{
常量observesList=[];
对于(让口袋妖怪的结果){
push(this.getPokemonByName(pokemon.name));
}
返回forkJoin(observablesList);
})
).订阅(res=>{
控制台日志(res);
//其余的在这里做
})
}

您可以像这样使用
forkJoin
-

getPokemons(pageNumber: number) : Observable<Pokemon[]> {
    var apiUrl = `${this.apiRoot}?&limit=${this.itemCount}&offset=${pageNumber * this.itemCount - (20)}`;
    return this.httpClient.get<any>(`${apiUrl}`)
               .pipe(
                      switchMap(res => {

                        //now you want to call getPokemonByName for each of the result your got in res.results
                        //so first create an array from getPokemonByName -
                        const observables$ = res.result.map(pokemon => this.getPokemonByName(pokemon.name));
                        return forkJoin(observables$);                        
                      })
                    );
  }

  getPokemonByName(name: string) : Observable<Pokemon> {
    return this.httpClient.get<Pokemon>(`${this.apiRoot}/${name}`).pipe(
      map(res => {
        return new Pokemon(res);
      })
    );
  }
}
getPokemons(页码:number):可观察{
var apirl=`${this.apiRoot}?&limit=${this.itemCount}&offset=${pageNumber*this.itemCount-(20)}`;
返回此.httpClient.get(`${apirl}`)
.烟斗(
开关映射(res=>{
//现在,您需要为res.results中获得的每个结果调用getPokemonByName
//因此,首先从getPokemonByName创建一个数组-
const observes$=res.result.map(pokemon=>this.getPokemonByName(pokemon.name));
返回forkJoin(可观测值$);
})
);
}
getPokemonByName(名称:string):可观察{
返回此.httpClient.get(`${this.apiRoot}/${name}').pipe(
地图(res=>{
归还新口袋妖怪(res);
})
);
}
}

现在您的
getPokemons
消费者应该订阅
getPokemons
返回的可观察值

您可以像这样使用
forkJoin
-

getPokemons(pageNumber: number) : Observable<Pokemon[]> {
    var apiUrl = `${this.apiRoot}?&limit=${this.itemCount}&offset=${pageNumber * this.itemCount - (20)}`;
    return this.httpClient.get<any>(`${apiUrl}`)
               .pipe(
                      switchMap(res => {

                        //now you want to call getPokemonByName for each of the result your got in res.results
                        //so first create an array from getPokemonByName -
                        const observables$ = res.result.map(pokemon => this.getPokemonByName(pokemon.name));
                        return forkJoin(observables$);                        
                      })
                    );
  }

  getPokemonByName(name: string) : Observable<Pokemon> {
    return this.httpClient.get<Pokemon>(`${this.apiRoot}/${name}`).pipe(
      map(res => {
        return new Pokemon(res);
      })
    );
  }
}
getPokemons(页码:number):可观察{
var apirl=`${this.apiRoot}?&limit=${this.itemCount}&offset=${pageNumber*this.itemCount-(20)}`;
返回此.httpClient.get(`${apirl}`)
.烟斗(
开关映射(res=>{
//现在,您需要为res.results中获得的每个结果调用getPokemonByName
//因此,首先从getPokemonByName创建一个数组-
const observes$=res.result.map(pokemon=>this.getPokemonByName(pokemon.name));
返回forkJoin(可观测值$);
})
);
}
getPokemonByName(名称:string):可观察{
返回此.httpClient.get(`${this.apiRoot}/${name}').pipe(
地图(res=>{
归还新口袋妖怪(res);
})
);
}
}
现在您的
getPokemons
消费者应该订阅
getPokemons
返回的可观察值

你不需要重新开始吗