Angular BehaviorSubject onSubscribe 事件/延迟加载 api 数据
Angular BehaviorSubject onSubscribe event / Lazy loading api data
我正在尝试在 Angular 5 中实现 HATEOAS api 数据的延迟加载。假设我有一个 class Car
,它包含对Engine
的实例,但只有在访问时才应加载引擎。
A class Car
:
export class Car {
private _engine = new BehaviorSubject<Engine>(null);
engine = _engine.asObservable()
constructor(
private enginesService
) {}
}
A class 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 的访问,这将 return 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
包装在 class 中,它提供 onSubscribe
事件。 Car
可以订阅 onSubscribe
事件,并且会知道什么时候尝试获取引擎值。有没有其他方法知道何时访问 engine
?
编辑:
funkizer 把我带到了冷观测。我更新了我的 Car
实现,以将引擎作为冷可观察对象提供。现在汽车甚至不需要知道引擎是否被访问,它只提供一次 observable,每次订阅都会触发 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 returns cold observables(只有当有人订阅时才会做任何事情),所以你不需要订阅 Car 中的 api 调用,以及 api 调用只会在需要时发生。您可以通过 shareReplay()
将 Observable 传递给模板,因此只有一个 api 请求。尝试:
engine$:Observable<Engine> = this.enginesService.getEngine().pipe(shareReplay(1))
<div *ngIf="car.engine$|async as engine">...
编辑: Full StackBlitz 示例:https://stackblitz.com/edit/angular-ea52a7?file=app%2Fapp.component.html
我正在尝试在 Angular 5 中实现 HATEOAS api 数据的延迟加载。假设我有一个 class Car
,它包含对Engine
的实例,但只有在访问时才应加载引擎。
A class Car
:
export class Car {
private _engine = new BehaviorSubject<Engine>(null);
engine = _engine.asObservable()
constructor(
private enginesService
) {}
}
A class 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 的访问,这将 return 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
包装在 class 中,它提供 onSubscribe
事件。 Car
可以订阅 onSubscribe
事件,并且会知道什么时候尝试获取引擎值。有没有其他方法知道何时访问 engine
?
编辑:
funkizer 把我带到了冷观测。我更新了我的 Car
实现,以将引擎作为冷可观察对象提供。现在汽车甚至不需要知道引擎是否被访问,它只提供一次 observable,每次订阅都会触发 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 returns cold observables(只有当有人订阅时才会做任何事情),所以你不需要订阅 Car 中的 api 调用,以及 api 调用只会在需要时发生。您可以通过 shareReplay()
将 Observable 传递给模板,因此只有一个 api 请求。尝试:
engine$:Observable<Engine> = this.enginesService.getEngine().pipe(shareReplay(1))
<div *ngIf="car.engine$|async as engine">...
编辑: Full StackBlitz 示例:https://stackblitz.com/edit/angular-ea52a7?file=app%2Fapp.component.html