我正在尝试在 Angular 5 中实现 HATEOAS API 数据的延迟加载。假设我有一个类Car
,其中包含对Engine
实例的引用,但引擎只有在被访问时才应加载。
A类Car
:
export class Car {
private _engine = new BehaviorSubject<Engine>(null);
engine = _engine.asObservable()
constructor(
private enginesService
) {}
}
A类Engine
:
export class Engine {
type: string;
}
一些模板可以通过组件变量访问Car
的实例car
,异步访问可观察到的引擎:
<div *ngIf="car.engine | async; let engine; else loadingEngine">
<p>{{engine.type}}</p>
</div>
<ng-template #loadingEngine>Loading engine...</ng-template>
上面,汽车不知道何时访问engine
,也不知道发动机必须从 API 加载。现在我尝试仅通过 getter 方法提供对 Car.engine 的访问,该方法将返回car.asObservable()
并触发 api 请求,如下所示:
export class Car {
private _engine = new BehaviorSubject<Engine>(null);
constructor(
private enginesService
) {}
engine(): Observable<Engine> {
this.enginesService.getEngine().subscribe( engine => {
_engine.next(engine);
)
return _engine.asObservable()
}
}
但是当在模板中使用该方法时,它被一遍又一遍地调用,导致许多 api 请求,导致浏览器崩溃。
我的想法是将BehaviorSubject
包装在一个提供onSubscribe
事件的类中。Car
可以订阅onSubscribe
事件,并知道何时有东西试图获取引擎值。有没有其他方法可以知道何时访问engine
?
编辑:
Funkizer把我带到了冷冰冰的可观察物。我更新了我的Car
实现,以将引擎作为冷可观察对象提供。现在汽车甚至不需要知道引擎是否被访问,它只需要提供一次可观察的,每个订阅都会触发 api 调用:
export class Car {
private _engine: Engine;
engine: Observable<Engine> = new Observable( observer => {
enginesService.getEngine().subscribe( engine => {
this._engine = engine;
observer.next(this._engine);
}
})
constructor(
private enginesService
) {}
}
HttpClient 返回冷可观察量(只会在有人订阅时执行任何操作),因此您无需在 Car 中订阅 api 调用,并且 api 调用只会在需要时发生。只需通过shareReplay()
将可观察量传递给模板,因此只有一个 api 请求。尝试:
engine$:Observable<Engine> = this.enginesService.getEngine().pipe(shareReplay(1))
<div *ngIf="car.engine$|async as engine">...
编辑:全栈闪电战示例:https://stackblitz.com/edit/angular-ea52a7?file=app%2Fapp.component.html