[英]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.