如何返回使用可观察对象发出的数据构造的数组?

时间:2019-07-03 11:50:29

标签: angular rxjs

我有一个接收服务返回的可观察对象的函数。我需要此函数来迭代Observable发出的数据,并根据接收到的数据构造一个数组。

我可以理解如何以所需的方式构造数组,但是我不明白的是如何返回数组。

getTop5Crypto() : string[] {

    let top5CryptoIds : string[] = [];
    this.cryptoService.getCryptoMarkets().subscribe(res => {
      let data = res.data;
      for(let i = 0; i < 5; i++) {
        top5CryptoIds.push(data[i].baseId)
      }
    });

    return top5CryptoIds; //<-- Will return empty array
  }

在上面的函数中,我构造了数组,然后返回它。但是,由于return命令在异步代码之外,因此它将在异步代码之前执行,这意味着该函数将返回一个空数组。

如果我将返回值放在next可观察函数的内部,使其位于异步代码内部,则编译器将给出错误,因为并非函数中的所有路径都将返回值。如果我在异步代码中有两个返回命令,一个在内部,一个在外部,那么我们又回到了第一个问题。

更新:全班学习

export class HomeComponent implements OnInit {

  //cryptos: string[] = ['bitcoin', 'ethereum', 'litecoin']
  cryptoDetails: CryptoDetail[];

  constructor(private cryptoService: CryptoService) { }

  ngOnInit() {
    this.cryptoDetails = new Array();

    let ids : string[] = this.getTop5Crypto();
    this.getCryptoData(ids);

    const source = interval(5000).subscribe(val => this.getCryptoData(ids))

  }

  getCryptoData(ids: string[]){
    this.cryptoDetails = [];
    console.log("get crypto")
    for(let crypto of ids){
      this.cryptoService.getCryptoInfo(crypto).subscribe(res => {
        let data = res.data;
        let cryptoDetail = new CryptoDetail(data.id, data.rateUsd, data.symbol);
        this.cryptoDetails.push(cryptoDetail);

      })
    }
  }

  async getTop5Crypto() : Promise<string[]> {

    let top5CryptoIds : string[] = [];
    await this.cryptoService.getCryptoMarkets().subscribe(res => {
      let data = res.data;
      for(let i = 0; i < 6; i++) {
        top5CryptoIds.push(data[i].baseId)
      }
    });

    return top5CryptoIds;
  }

3 个答案:

答案 0 :(得分:1)

您可以使用switchMap()使用from()来发射每个数组项,然后映射到baseId来发射ID。如果要限制发射的数量,请使用take(5),最后使用toArray()将所有值作为数组发射。

getTop5Crypto() : Observable<string[]> {
    return this.cryptoService.getCryptoMarkets().pipe(
        switchMap(res => from(res.data)),
        map(data => data.baseId),
        take(5),
        toArray()
    );
}

答案 1 :(得分:-1)

为此,您不应该订阅可观察的对象,可以返回带值的可观察对象或使用async / await,使用toPromise()将您的可观察对象转换为Promise。

在您的情况下,您返回的值在返回时无法解析

async getTop5Crypto() : Promise<string[]> {

    let top5CryptoIds : string[] = [];
    let top5CryptoIds = await this.cryptoService.getCryptoMarkets()
    .pipe(
      switchMap(res => {
        let data = res.data;
        for(let i = 0; i < 5; i++) {
          top5CryptoIds.push(data[i].baseId)
       }
     });
    ).toPromise()

retrun top5CryptoIds 


  }

答案 2 :(得分:-1)

通常,最佳做法是返回一个可观察的数据而不是内部数据。

如果您仍然想读取该值,则可以使用take(1)进行“一次性读取”:

getTop5Crypto() : string[] {

    let top5CryptoIds : string[] = [];
    this.cryptoService.getCryptoMarkets().pipe(take(1)).subscribe(res => {
      let data = res.data;
      for(let i = 0; i < 5; i++) {
        top5CryptoIds.push(data[i].baseId)
      }
    });

    return top5CryptoIds;
  }
  

当您只对第一个发射感兴趣时,您想使用   采取。也许您想看看用户在他们第一次点击时   进入页面,或者您想订阅点击事件   并进行第一次发射。另一个用例是当您需要   在特定时间点拍摄数据快照,但不要   需要进一步的排放。例如,用户令牌流   更新,或基于Angular应用程序中的流的路由防护。