Angular Asyn c функции OnInit - PullRequest
1 голос
/ 08 мая 2020

надеюсь, у вас хороший день. У меня проблема с обработкой вызовов asyn c в 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 () в кнопку, но это не совсем мое намерение. У меня была эта проблема раньше, и я хотел бы решить ее должным образом. Итак, вопрос в том, как мне дождаться его завершения, чтобы запустить следующую функцию.

Любая помощь приветствуется! ?‍?

Ответы [ 3 ]

1 голос
/ 08 мая 2020
Решение

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

Это станет немного более читаемым.

Получить совпадений . Как только вы закончите, получите пользователей.

Просто для завершения и наглядности вы можете преобразовать Observable, возвращенный на _matchService.getMatchs(), в Promise, поработать над ним, а затем вернуть его.

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

Надеюсь, это поможет.

1 голос
/ 08 мая 2020

как видите, есть несколько различных решений вашей проблемы. Мой совет - продолжать использовать наблюдаемую цепочку и подождать, пока не закончит 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 из angular.

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 в объект, чтобы проще и быстрее проверять дубликаты.

Удачного кодирования!

1 голос
/ 08 мая 2020

Один из способов - разместить 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)
    }

...