使用Angular中的Observables返回循环的API调用值

时间:2019-02-07 06:45:12

标签: angular api asynchronous rxjs observable

我正在尝试获取一个返回API调用的循环。使用Spotify API,我可以根据名称生成艺术家的ID,因此在代码的前面,我生成了名称列表,并保存在数组中。出于测试目的,我使用的虚拟数组的值与先前的API调用将返回的值相同。

  getAllSpotifyArtistIds(){
    let dummyArtistList = ['loren north', 'Randy Emata', 'Dyekho', 'The Lemon Twigs', 'The Toasters'];
    for (let i = 0; i < dummyArtistList.length; i++) {
      this.artistToQuery = dummyArtistList[i];
      this.generateArtistIdFromArtist(dummyArtistList[i]).subscribe((response) => {
      this.newProperty.push(response); //this is a class property I'm hoping to populate with this response.
      })
    }
  }

函数generateArtistIdFromArtist(artistName:string)每次被调用时都会返回一个值,这是从Spotify API中查询的艺术家ID。

从spotify生成Arist ID的代码如下:

  generateArtistIdFromArtist(artistName){
    return this.spotifyService.getToken().pipe( 
      flatMap((accessTokenResponse) => {
        return this.spotifyService.searchArtistID(artistName, accessTokenResponse.access_token)
        .map((response) => {
          response.artists.items.forEach((spotifyArtist) => {
            this.spotifyArtistListFromQuery.push(spotifyArtist.name);
          });
          const artistMatchIndexPosition = this.spotifyArtistListFromQuery.findIndex((artistToQueryNow) => {
            return artistToQueryNow === artistName;
          });
          //Spotify returns multiple artists with similar names, so check for identical match
          if (artistMatchIndexPosition >= 0 ){
             this.artistIdListFromSpotify.push(response.artists.items[artistMatchIndexPosition].id)
             return response.artists.items[artistMatchIndexPosition].id;
                // finally return the id of the artist if there's a match
          }
        });
      })
    );
  }

我曾尝试在各个地方放置setTimeout(),但是我想我只是不太了解异步编码,以至于不知道自己在做什么。我以为也许强迫一些暂停可能会让循环赶上来。此时,我只得到3个值。

我期望在dummyArtistList中为每个艺术家返回Spotify结果,但仅返回一些结果,并且它们在某种程度上是不正确的。

如果您将单个名称传递给它,这将非常有效,但是如果您开始执行多个操作,则循环会失败,如果重复执行三个操作,则循环将导致完全错误的结果。我是编码(特别是异步)的新手,所以我很难理解为什么我无法让循​​环等待API调用以可观察对象完成。我确信这与以下事实有关:循环本身不是异步的,并且API调用是,对将其分类的任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:0)

您需要的是一组可观察的数组,即来自rxjs的concat运算符,并对其进行订阅。了解有关concat here的更多信息。

您可以这样导入concat:

  

从'rxjs / operators'导入{concat};

  getAllSpotifyArtistIds() {
    const APICallArray = [];
    const dummyArtistList = ['loren north', 'Randy Emata', 'Dyekho', 'The Lemon Twigs', 'The Toasters'];

    for (let i = 0; i < dummyArtistList.length; i++) {
        this.artistToQuery = dummyArtistList[i];
        APICallArray.push(this.generateArtistIdFromArtist(dummyArtistList[i]));
     }
     concat(...APICallArray).subscribe((res) => {
         res.map((response) => {
            response.artists.items.forEach((spotifyArtist) => {
              this.spotifyArtistListFromQuery.push(spotifyArtist.name);
            });

            const artistMatchIndexPosition = this.spotifyArtistListFromQuery.findIndex((artistToQueryNow) => {
                return artistToQueryNow === artistName;
            });
            if (artistMatchIndexPosition >= 0 ) {
                this.artistIdListFromSpotify.push(response.artists.items[artistMatchIndexPosition].id);
                this.newProperty.push(response.artists.items[artistMatchIndexPosition].id);
            }
        });
     });
}

  generateArtistIdFromArtist(artistName) {
        return this.spotifyService.getToken().pipe(
          flatMap((accessTokenResponse) => {
            return this.spotifyService.searchArtistID(artistName, accessTokenResponse.access_token);
                 })
        );
    }

答案 1 :(得分:0)

您也可以使用forkJoin进行此操作,因为您希望将所有结果存储在一个数组中。

将所有observables保存在一个临时数组中,并使用forkJoin运算符进行订阅

getAllSpotifyArtistIds(){
    let dummyArtistList = ['loren north', 'Randy Emata', 'Dyekho', 'The Lemon Twigs', 'The Toasters'];
    let artistSet = [];
    for (let i = 0; i < dummyArtistList.length; i++) {
      this.artistToQuery = dummyArtistList[i];
      artistSet.push(this.generateArtistIdFromArtist(dummyArtistList[i]))
    }
     forkJoin(...artistSet).subscribe((response) => {
          //Here response is an array and you can simply assign
          this.newProperty = response;
     })
  }

答案 2 :(得分:0)

由于@Ritesh的帮助,我得以弄清楚如何解决此问题。

最后两个功能是

  generateArtistIdFromArtist(artistName) {
      return this.spotifyService.getToken().pipe(
        flatMap((accessTokenResponse) => {
          return this.spotifyService.searchArtistID(artistName, accessTokenResponse.access_token);
               })
      );
  }

,然后返回包含艺术家的信息数组,使用此调用,APICallArray本身实际上就已拥有该信息,无需明显地订阅。我仍然不完全了解这是什么产生的,但是我能够得到所有答案。

  getAllSpotifyArtistIds() {
    const APICallArray = [];
    const dummyArtistList = ['loren north', 'Randy Emata', 'Dyekho', 'The Lemon Twigs', 'The Toasters'];
    const ArtistOutputArray = [];
    for (let i = 0; i < dummyArtistList.length; i++) {
      this.artistToQuery = dummyArtistList[i];
      APICallArray.push(this.generateArtistIdFromArtist(dummyArtistList[i]));
    }

    for (let i = 0; i < APICallArray.length; i++) {
        APICallArray[i].subscribe((response) => {
          ArtistOutputArray.push(response);
        });
    }
    return ArtistOutputArray;
  }

谢谢@Ritesh!