簡體   English   中英

Angular 異步函數 OnInit

[英]Angular Async functions OnInit

我在處理 ngOninit() 上的異步調用時遇到了這個問題。 基本上我需要按順序加載一些東西,但我不知道如何。

這是代碼:

    import { Component, OnInit } from '@angular/core';
    import { Match, Game, participantIdentities, player } from '../../models/match';
    import { MatchService } from '../../services/match.service';
    import { Global } from '../../services/global';
    import { Observable } from 'rxjs';

    @Component({
      selector: 'app-players',
      templateUrl: './players.component.html',
      styleUrls: ['./players.component.css'],
      providers: [MatchService]
    })
    export class PlayersComponent implements OnInit {
      public matchs: Array<Match>;
      public games: Array<Game>
      public player: Array<player>;
      public players: []
      constructor(
        private _matchService: MatchService
      ) { 
        this.games = []
        this.player = []
      }

      ngOnInit(): void {
        this.getMatchs()
      }

      getMatchs(){
          this._matchService.getMatchs().subscribe(
            response =>{
              
              this.matchs = response.matchs;
              console.log(this.matchs);
              for(let i = 0; i<this.matchs.length; i++){
                this.games[i] = this.matchs[i].game;
              };
              console.log(this.games)
            }
            ,error=>{
              console.log(<any>error)
            }
          );
        }
      getUsers(){
          let accountId = [];
          for(let i = 0; i < this.matchs.length; i++){
            for(let x = 0; x < this.matchs[i].game.participantIdentities.length; x++){
              if ( typeof(accountId.find(element=>element == this.matchs[i].game.participantIdentities[x].player.summonerName)) === "undefined"){
                accountId.push(this.matchs[i].game.participantIdentities[x].player.summonerName)
                this.player.push(this.matchs[i].game.participantIdentities[x].player)
              }
            } 
          }
          console.log(this.player)
        }
    }

如您所見,getUsers() function 使用的數據來自 getMatchs()。 如果我在 ngOninit getUsers() 上執行這兩個函數,它會拋出一個錯誤,因為另一個還沒有完成。 這是有道理的。 當然,我可以將 getUsers() 合並到一個按鈕中,但這並不是我的真正意圖。 我以前遇到過這個問題,我很想妥善解決它。 所以問題是,我如何等待它完成才能運行下一個 function。

一種方法是在this.matchs = response.matchs;之后放置getUsers() ,然后每次調用getMatchs時,它也會調用getUsers

另一種方法是將訂閱移至 ngOnInit。


  ngOnInit(): void {
    this.getMatchs().subscribe(response => {
      this.matchs = response.matchs;
      for(let i = 0; i<this.matchs.length; i++){
        this.games[i] = this.matchs[i].game;
      };
      this.getUsers();
    });
  }

getMatchs(){
      return this._matchService.getMatchs();
    }

  getUsers(){
      let accountId = [];
      for(let i = 0; i < this.matchs.length; i++){
        for(let x = 0; x < this.matchs[i].game.participantIdentities.length; x++){
          if ( typeof(accountId.find(element=>element == this.matchs[i].game.participantIdentities[x].player.summonerName)) === "undefined"){
            accountId.push(this.matchs[i].game.participantIdentities[x].player.summonerName)
            this.player.push(this.matchs[i].game.participantIdentities[x].player)
          }
        } 
      }
      console.log(this.player)
    }

@satanTime 的解決方案很好。
但是,如果您不想錯過getUsers()調用,我想提供另一種解決方案。

您可以嘗試使用Promises

getMatchs(): Promise<void> {
    return new Promise((resolve, reject) => {
        this._matchService.getMatchs().subscribe(
            response => {
                // Do whatever you need
                resolve();
            },
            error => {
                // Handle error
                // reject(); if you want to scale the exception one level upwards.
            }
        );
    });
}

然后,像這樣重寫您的ngOnInit方法

ngOnInit(): void {
    this.getMatchs().then(() => {
        this.getUsers();
    });
}

這變得更具可讀性。

獲取匹配項 完成后,獲取用戶。

只是為了完成和幻想,您可以將_matchService.getMatchs()返回的Observable轉換為Promise ,處理它,然后返回它。

getMatchs = (): Promise<void> => 
    this._matchService.getMatchs().toPromise()
        .then(response => {
            // Do whatever you need
        })
        .catch(err => {
            // Handle error
        });

希望能幫助到你。

如您所見,您的問題有幾種不同的解決方案。 我的建議是繼續使用可觀察鏈並等到 getMatchs 完成。 例如:

ngOnInit(): void {
  this.getMatchs().subscribe(res => this.getUsers());
}

那么您將不得不像這樣更改您的 getmatchs 函數:

getMatchs() {
  this._matchService.getMatchs().pipe(
    tap(result => {
      this.matchs = response.matchs;
      this.games = this.matchs.map(m => m.game);
    })
  );  

通過這樣做,您可以繼續使用可觀察的 stream。

這應該可行,但您應該注意其他問題。 其中之一是取消訂閱您想要避免應用程序中的 memory 泄漏的每個訂閱是一個非常好的做法。 您可以通過手動調用unsubscribe()或依賴來自 angular 的async pipe 來執行此操作。

https://rxjs-dev.firebaseapp.com/guide/subscription

https://angular.io/api/common/AsyncPipe

另一方面,如果您可以修改代碼以減少對相同信息執行的循環數量,您將獲得更好的性能。 查看我為您做的另一個版本的 GetMatchs(未測試),但希望可以讓您了解如何提高組件的性能:

processMatches() {
   this._matchService.getMatches().pipe(
      tap(response => {
         this.matches = response.matchs;
         let accountId = {};            

         this.matches.forEach((m, index) => {
            this.game[index] = m[index].game;
            this.game[index].participantIdentities
                .forEach(p => {
                    if (!accountId[p.player.sumonerName]) {
                        accountId[p.player.sumonerName] = p.player.sumonerName;
                        this.player.push(p.player);
                    }
                });      
             });

         })
     )
 }

同樣,此代碼未經過測試,這里的想法是減少循環並將 accountId 數組轉換為 object 以便更輕松、更快地檢查重復項

快樂編碼!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM