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

一种方法是将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)
}

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

希望能有所帮助。

正如您所看到的,您的问题有几种不同的解决方案。我的建议是继续使用可观察的链,等待Matchs完成。例如:

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

然后你必须像这样更改你的getmatches函数:

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

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

这应该有效,但还有其他问题你应该意识到。其中之一是,取消订阅您想要的每一个订阅都是一个非常好的做法,以避免应用程序中的内存泄漏。您可以通过手动调用unsubscribe()或从angular依赖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数组转换为对象,以便更容易、更快地检查重复项。

编码快乐!

最新更新