Angular 订阅observable后未定义的字符串[]
下面的代码给出了一个运行时错误,因为Angular 订阅observable后未定义的字符串[],angular,rxjs,Angular,Rxjs,下面的代码给出了一个运行时错误,因为top5Ids未定义。我真的不明白,当我正确地订阅observable并从订阅方next方法内部设置top5Ids变量时,为什么这个变量没有定义 cryptoService类只是返回http.get()函数的结果,该函数是可观察的 export class HomeComponent implements OnInit { cryptoDetails: CryptoDetail[]; top5Ids: string[]; constructor
top5Ids
未定义。我真的不明白,当我正确地订阅observable并从订阅方next
方法内部设置top5Ids
变量时,为什么这个变量没有定义
cryptoService类只是返回http.get()函数的结果,该函数是可观察的
export class HomeComponent implements OnInit {
cryptoDetails: CryptoDetail[];
top5Ids: string[];
constructor(private cryptoService: CryptoService) { }
ngOnInit() {
this.cryptoDetails = new Array();
this.getTop5Crypto();
this.getCryptoData(this.top5Ids);
const source = interval(5000).subscribe(val => this.getCryptoData(this.top5Ids))
}
getCryptoData(ids: string[]){
this.cryptoDetails = [];
console.log("get crypto")
for(let id of ids){
this.cryptoService.getCryptoInfo(id).subscribe(res => {
let data = res.data;
let cryptoDetail = new CryptoDetail(data.id, data.rateUsd, data.symbol);
this.cryptoDetails.push(cryptoDetail);
})
}
this.cryptoDetails.sort();
}
getTop5Crypto() : void {
let top5CryptoIds : string[] = [];
this.cryptoService.getCryptoMarkets().pipe(take(1)).subscribe(res => {
let data = res.data;
for(let i = 0; i < 6; i++) {
top5CryptoIds.push(data[i].baseId)
}
this.top5Ids = top5CryptoIds;
});
}
}
导出类HomeComponent实现OnInit{
cryptoDetails:CryptoDetail[];
top5id:string[];
构造函数(私有加密服务:加密服务){}
恩戈尼尼特(){
this.cryptoDetails=新数组();
this.getTop5Crypto();
this.getCryptoData(this.top5Ids);
const source=interval(5000).subscribe(val=>this.getCryptoData(this.top5Ids))
}
getCryptoData(ID:字符串[]){
this.cryptoDetails=[];
log(“获取加密”)
for(让id中的id){
this.cryptoService.getCryptoInfo(id).subscribe(res=>{
设data=res.data;
let cryptoDetail=新的cryptoDetail(data.id、data.rateUsd、data.symbol);
this.cryptoDetails.push(cryptoDetail);
})
}
this.cryptoDetails.sort();
}
getTop5Crypto():void{
让top5CryptoIds:string[]=[];
this.cryptoService.getCryptoMarkets().pipe(take(1)).subscribe(res=>{
设data=res.data;
for(设i=0;i<6;i++){
top5CryptoIds.push(数据[i].baseId)
}
this.top5Ids=top5CryptoIds;
});
}
}
在Angular中,最好完全采用功能性反应式编程。
您可以按以下方式重写代码:
export class HomeComponent implements OnInit {
cryptoDetails: CryptoDetail[];
top5Ids$: Observable<string[]>;
constructor(private cryptoService: CryptoService) { }
ngOnInit() {
this.top5Ids$ = this.getTop5Crypto();
timer(0, 5000).pipe(
switchMap(() => this.top5Ids$),
switchMap((top5Ids) => this.getCryptoData(top5Ids))
).subscribe((cryptoDetails) => {
this.cryptoDetails = cryptoDetails;
})
}
getCryptoData(ids: string[]): Observable<CryptoDetail[]> {
return forkJoin(ids.map(id => this.cryptoService.getCryptoInfo(id)))
.pipe(
map(responses => responses.map(r => new CryptoDetail(r.data.id, r.data.rateUsd, r.data.symbol)).sort())
);
}
getTop5Crypto() : Observable<string[]> {
return this.cryptoService.getCryptoMarkets().pipe(
take(1),
map((res: any) => res.data.filter((d, i) => i < 5).map(d => d.baseId)),
);
}
}
导出类HomeComponent实现OnInit{
cryptoDetails:CryptoDetail[];
top5Ids$:可观察;
构造函数(私有加密服务:加密服务){}
恩戈尼尼特(){
this.top5Ids$=this.getTop5Crypto();
计时器(0,5000)。管道(
switchMap(()=>this.top5Ids$),
switchMap((top5Ids)=>this.getCryptoData(top5Ids))
).订阅((加密详细信息)=>{
this.cryptoDetails=cryptoDetails;
})
}
getCryptoData(ID:string[]):可观察{
返回forkJoin(id.map(id=>this.cryptoService.getCryptoInfo(id)))
.烟斗(
map(responses=>responses.map(r=>newcryptodetail(r.data.id,r.data.rateud,r.data.symbol)).sort())
);
}
getTop5Crypto():可观察{
返回此.cryptoService.getCryptoMarkets()管道(
以(1)为例,
map((res:any)=>res.data.filter((d,i)=>i<5.map(d=>d.baseId)),
);
}
}
函数式反应式编程的思想是,我们编写代码,对DOM事件和Http响应等事件作出反应,然后通过一系列(理想情况下是纯)函数将转换应用于与这些事件相关联的数据
我们尽量避免在管道末端创建手动订阅(如果使用角度异步管道,有时甚至不会)。通过这种方式,我们获得了一个很好的可预测的异步事件管道,并避免了诸如竞争条件之类的问题
需要注意的是,要做这些事情,您必须对RxJS有深刻的理解。您订阅了observable,因为它是异步发射的。即在方法getTop5Crypto()返回很久之后。这就像你发送电子邮件一样:你不能期望在发送电子邮件后立即从响应中提取数据。只有在电子邮件客户端通知你响应已返回时,你才能这样做。@JBNizet太好了。但是我如何修复这个代码呢?例如,通过阅读patjim给你的答案。但最重要的是,通过稍微远离这段代码,阅读和练习异步,RxJS。回答得不错!这是反应的方式。谢谢!。稍有改进-无需在
getCryptoData
中执行(ids)的。请看我的编辑。谢谢你的回答!我现在正在努力。但是,对于getTop5Crypto中的下一行,{}
类型上不存在属性“data”<代码>映射(res=>res.data.filter((d,i)=>i<5.map(d=>d.baseId)),
,这使我无法编译类型脚本无法推断res
的类型,您需要明确地将其键入any
-请参阅我的编辑。