Angular 2+跨服务调用问题:getPrivateLessons返回undefined如何解决?
问题根源:异步操作的时序问题
你遇到的问题本质是HTTP请求的异步特性导致的:
- 当
ParametrsResultsService的构造函数执行时,会立刻发起HTTP请求,但请求完成需要时间,subscribe里的回调函数要等请求成功后才会把数据赋值给privateLessons。 - 而你的组件很可能在请求还没完成时就调用了
getPrivateLessons()方法,这时候privateLessons还是初始的undefined,所以返回空。
虽然你在subscribe里能打印出数据,但那是请求完成后的异步回调,和组件调用方法的时机是完全错开的。
解决方案
下面提供两种常用的解决思路,你可以根据业务场景选择:
方案1:直接代理Observable(最简单,适合不需要缓存的场景)
既然HTTP请求本身是Observable,我们可以让ParametrsResultsService的getPrivateLessons()直接返回这个Observable,把订阅的操作交给组件去做,这样就能保证拿到完整的数据:
@Injectable() export class ParametrsResultsService { constructor(private _privateLessonsService: PrivateLessonsService) {} getPrivateLessons() { // 直接返回原服务的Observable,让调用方订阅 return this._privateLessonsService.getPrivateLessons(); } }
组件中使用方式:
constructor(private _parametrsResultsService: ParametrsResultsService) { this._parametrsResultsService.getPrivateLessons() .subscribe(lessons => { // 这里就能拿到完整的 lessons 数据了 console.log(lessons); // 可以把数据赋值给组件的属性供模板使用 this.privateLessons = lessons; }); }
方案2:用BehaviorSubject缓存数据(适合需要在服务内复用数据的场景)
如果希望服务内部缓存已经获取到的课程数据,避免重复发起HTTP请求,可以用RxJS的BehaviorSubject来存储数据。它既可以保存当前值,又能对外提供Observable供订阅:
import { BehaviorSubject } from 'rxjs'; @Injectable() export class ParametrsResultsService { // 初始化一个空数组作为默认值 private _privateLessonsSubject = new BehaviorSubject<PrivateLesson[]>([]); // 对外暴露只读的Observable,防止外部直接修改数据 public privateLessons$ = this._privateLessonsSubject.asObservable(); constructor(private _privateLessonsService: PrivateLessonsService) { // 初始化时发起请求,拿到数据后更新Subject this._privateLessonsService .getPrivateLessons() .subscribe(responseData => { this._privateLessonsSubject.next(responseData); }); } // 如果需要同步获取当前缓存的数据 getPrivateLessons() { return this._privateLessonsSubject.value; } }
组件中使用方式:
如果想实时监听数据变化(包括初始加载),可以订阅privateLessons$:
constructor(private _parametrsResultsService: ParametrsResultsService) { this._parametrsResultsService.privateLessons$ .subscribe(lessons => { // 这里会在数据加载完成后触发,后续如果数据更新也会再次触发 this.privateLessons = lessons; }); }
如果确定数据已经加载完成,也可以直接调用getPrivateLessons()获取当前值,但要注意初始值是空数组,需要做判断。
额外建议
尽量避免在服务的构造函数里发起HTTP请求,因为构造函数是同步执行的,过早发起请求可能会导致不必要的资源消耗。更好的做法是在组件调用服务的方法时再触发请求,或者用APP_INITIALIZER在应用初始化时提前加载必要数据(这是进阶用法)。
内容的提问来源于stack exchange,提问作者lampka w tubce
相关产品推荐
相关产品推荐

