调用Angular Service时组件获取数据为undefined的原因排查
为什么Angular组件调用Service获取数据时返回undefined?
我正在使用JSONPlaceholder Fake API获取数据,在Service中能够获取到API返回的数据,但在AppComponent中调用该Service时却得到undefined。以下是我的代码:
Service.ts 代码
import { Injectable } from '@angular/core'; import { Http, URLSearchParams, Response, RequestOptions, Headers } from '@angular/http'; import 'rxjs/RX'; import 'rxjs/add/operator/map'; @Injectable() export class InfiniteService { apiRoot: string = 'https://jsonplaceholder.typicode.com/comments?'; postId = 1; data; constructor(private _http: Http) { this._http.get(this.apiRoot).subscribe((data) => { this.data = data.json(); }); } init() { return this.data; } }
组件代码
import { Component, OnInit } from '@angular/core'; import { InfiniteService } from './infinite.service'; import 'rxjs/add/operator/map'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { data; constructor(private _infinteService: InfiniteService) { this.data = this._infinteService.init(); console.log(this.data); } GetPosition($event) { if ($event == 'Bottom') { console.log($event); } else { console.log($event); } } ngOnInit() { } }
问题根源:异步操作的时机问题
你看哈,HTTP请求是异步操作——当你在Service的构造函数里发起this._http.get()请求时,浏览器会后台去请求数据,这时候代码不会等着请求完成,而是继续往下走。
当AppComponent的构造函数调用this._infinteService.init()时,Service里的HTTP请求大概率还没完成,this.data还没被赋值,所以自然返回undefined。
修正方案:用Observable传递异步数据
咱们得换个思路,不要在Service里存数据然后同步返回,而是让Service返回HTTP请求的Observable,组件自己订阅这个Observable,等数据回来再处理。
修正后的Service代码
import { Injectable } from '@angular/core'; import { Http, URLSearchParams, Response, RequestOptions, Headers } from '@angular/http'; import 'rxjs/RX'; import 'rxjs/add/operator/map'; @Injectable() export class InfiniteService { apiRoot: string = 'https://jsonplaceholder.typicode.com/comments?'; postId = 1; constructor(private _http: Http) { } // 把请求封装成返回Observable的方法 getData() { return this._http.get(this.apiRoot) .map((response: Response) => response.json()); // 直接在Service里处理json转换 } }
修正后的组件代码
import { Component, OnInit } from '@angular/core'; import { InfiniteService } from './infinite.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { data; constructor(private _infinteService: InfiniteService) { } // 把数据获取逻辑放到ngOnInit里(Angular推荐的初始化时机) ngOnInit() { this._infinteService.getData().subscribe((result) => { this.data = result; console.log(this.data); // 这时候数据就有了! }); } GetPosition($event) { if ($event == 'Bottom') { console.log($event); } else { console.log($event); } } }
额外小提示
- 尽量不要在组件构造函数里做数据获取操作,
ngOnInit是Angular专门用来做初始化逻辑的钩子,更合适。 - 如果你需要复用获取到的数据,可以在Service里缓存Observable或者数据,避免重复发起请求。
内容的提问来源于stack exchange,提问作者Chellappan 喈�,angular"
相关产品推荐
相关产品推荐

