【问题标题】:Angular Async functions OnInit角度异步函数 OnInit
【发布时间】:2020-08-23 12:17:04
【问题描述】:

我在处理 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() 函数使用的数据来自 getMatchs()。如果我在 ngOninit getUsers() 上执行这两个函数,它会抛出一个错误,因为另一个还没有完成。这是有道理的。当然,我可以将 getUsers() 合并到一个按钮中,但这并不是我的真正意图。我以前遇到过这个问题,我很想妥善解决它。所以问题是,我如何等待它完成才能运行下一个函数。

【问题讨论】:

    标签: angular typescript asynchronous httprequest


    【解决方案1】:

    一种方法是将getUsers() 放在this.matchs = response.matchs; 之后,然后每次调用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)
        }
    
    

    【讨论】:

    • 很高兴听到,这不是一个理想的解决方案,只是一个简单的例子来展示解决它的可能方法。如果我可以在这里提供更多帮助,请随时告诉我。
    【解决方案2】:

    @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
            });
    

    希望对你有帮助。

    【讨论】:

    • 是的,它有帮助,我正在寻找如何正确使用 Promise,但没有取得多大成功,我最终做出了与 @satanTime 的建议类似的东西。我还有很多工作要做,所以欢迎任何信息。非常感谢。
    【解决方案3】:

    如您所见,有几种不同的解决方案可以解决您的问题。我的建议是继续使用可观察链并等到 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);
        })
      );  
    

    通过这样做,您可以继续使用您的可观察流。

    这应该可行,但您应该注意其他问题。其中之一是取消订阅您想要避免应用程序中的内存泄漏的每个订阅是一种非常好的做法。您可以通过手动调用unsubscribe() 或从角度依赖async 管道来完成此操作。

    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 数组转换为对象,以便更轻松、更快地检查重复项

    编码愉快!

    【讨论】:

    • 非常有用的信息,我没想过使用 .map(我还不完全理解它是如何工作的)。我在我的程序的几个实例中遇到了这个问题,所以我越了解它越好。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2021-01-11
    • 2020-05-30
    • 2017-09-22
    • 2021-10-25
    • 1970-01-01
    • 2020-09-29
    • 2018-08-15
    • 2021-03-09
    相关资源
    最近更新 更多