Angular组件调用DataService获取API数据时提示undefined如何解决
问题排查与解决
问题根源
这是典型的异步请求时序问题:
Angular的HttpClient返回的Observable都是异步执行的,调用getData()方法后,forkJoin触发的三个HTTP请求不会阻塞后续代码执行。你在ngOnInit里调用完getData()立刻读取dataService的数组变量时,HTTP请求的响应还没有返回,subscribe的回调函数还没执行,数组自然还没被赋值,所以打印出来是undefined。Network里能看到请求成功,只是说明请求响应已经完成,但执行顺序晚于你读取变量和打印的代码。
解决方案
提供两种常用落地方式:
方案1:让getData返回Observable,组件侧订阅(最推荐)
避免在Service内部订阅导致的时序不可控问题,代码修改如下:
// DataService修改后的getData方法 getData(): Observable<[Book[], User[], Card[]]> { const observableList: Observable<any>[] = [ this.getBooks(), this.getUsers(), this.getCards() ]; // 直接返回forkJoin的Observable,不在service内部订阅 return forkJoin(observableList) as Observable<[Book[], User[], Card[]]>; }
// MainComponent的ngOnInit修改后 ngOnInit() { this.dataService.getData().subscribe(resultList => { // 等请求全部返回后再执行赋值和打印 this.dataService.books = resultList[0]; this.dataService.users = resultList[1]; this.dataService.cards = resultList[2]; this.books = resultList[0]; this.users = resultList[1]; this.cards = resultList[2]; console.log(this.books); // 此时就能正常拿到数据 }); }
方案2:Service用可观察对象存储数据(适合多组件共享数据场景)
如果需要把数据存在Service里供多个组件共用,可以将存储变量改成BehaviorSubject:
// DataService修改部分代码 import { BehaviorSubject } from 'rxjs'; // 替换原有的数组变量定义 private books$ = new BehaviorSubject<Book[]>([]); private users$ = new BehaviorSubject<User[]>([]); private cards$ = new BehaviorSubject<Card[]>([]); // 暴露只读的Observable给外部订阅 get books() { return this.books$.asObservable(); } get users() { return this.users$.asObservable(); } get cards() { return this.cards$.asObservable(); } getData() { const observableList: Observable<any>[] = [ this.getBooks(), this.getUsers(), this.getCards() ]; forkJoin(observableList).subscribe(resultList => { // 数据返回后更新Subject的值 this.books$.next(resultList[0] as Book[]); this.users$.next(resultList[1] as User[]); this.cards$.next(resultList[2] as Card[]); }); }
// MainComponent的ngOnInit修改后 ngOnInit() { this.dataService.getData(); // 订阅数据变化,数据更新时自动触发回调 this.dataService.books.subscribe(books => { this.books = books; console.log(this.books); }); this.dataService.users.subscribe(users => this.users = users); this.dataService.cards.subscribe(cards => this.cards = cards); }
内容的提问来源于stack exchange,提问作者manti13
相关产品推荐
相关产品推荐

