我的 Angular 11 应用程序中有一个组件,它使用特定的服务类从 REST API 请求地址信息。该服务类在中继 API 响应的字段中缓存一些可观察值。这本质上允许组件内的多个依赖项都从 API 获取响应对象,而无需发出多个冗余 API 请求。
问题是我需要在每次用户导航到该页面时重新创建此服务对象。不幸的是,我无法为我的服务类获得所需的生命周期,因此,缓存的可观察量的生存时间太长,导致我的应用程序随着时间的推移在陈旧的 API 数据上运行。示例代码如下。
服务等级:
@Injectable()
export class ScopedAddressDS {
constructor(private readonly addressDS: AddressDS) {}
private readonly addressCache = new Map<number, Observable<Address>>();
public observeAddress(clientId: number): Observable<Address> {
if (!this.addressCache.has(clientId)) {
this.addressCache.set(clientId, from(this.addressDS.getAddress({id: clientId})).pipe(shareReplay(1)));
}
return this.addressCache.get(clientId);
}
}
注册(在组件 module.ts 级别):
const routes: Routes = [{
path: '',
component: ItemDetailsComponent,
data: {
breadcrumb: 'Item Details'
}
}];
@NgModule({
imports: [
RouterModule.forChild(routes),
// others...
],
declarations: [
ItemDetailsComponent,
// others...
],
providers: [
ScopedAddressDS,
// others...
],
})
export class ItemsDetailsModule {}
以及组件如何注入服务类的示例(请注意,此类具有其他依赖项,它们本身也依赖于同一服务类;这就是数据中继/共享的方式):
@Component({
selector: 'item-details',
templateUrl: './item-details.component.html',
styleUrls: ['./item-details.component.scss'],
providers: [BreadcrumbsService],
})
export class ItemDetailsComponent implements OnInit, OnDestroy {
constructor(
private scopedAddressDS: ScopedAddressDS
// etc...
) {
}
}
我在研究时发现的一个潜在解决方案是,一条路线可能具有
providers
,但由于我的应用程序(目前)停留在 Angular 11 中,这对我来说似乎不是一个选择。
假设我的整体设计和对 DI 的依赖没有缺陷,我如何构建我的类型注册,以便获得所需的生命周期范围(也就是说,每次用户导航到我的
ScopedAddressDS
实例时都会重新创建取决于它的页面)?
您可以在导航端使用路由器的
event
来重置缓存。另一种方法是在组件销毁时调用重置,但第一种方法更通用。
我使用map
clear
方法来清空缓存。
@Injectable()
export class ScopedAddressDS {
private sub: Subscription = new Subscription();
constructor(private readonly addressDS: AddressDS) {}
private readonly addressCache = new Map<number, Observable<Address>>();
public observeAddress(clientId: number): Observable<Address> {
if (!this.addressCache.has(clientId)) {
this.addressCache.set(
clientId,
from(this.addressDS.getAddress({ id: clientId })).pipe(shareReplay(1))
);
}
return this.addressCache.get(clientId);
}
constructor() {
this.sub.add(
(this.firstChildData$ = this.router.events
.pipe(filter((e): e is NavigationEnd => e instanceof NavigationEnd))
.subscribe(() => {
this.addressCache.clear();
}))
);
}
ngOnDestroy() {
this.sub.unsubscribe();
}
}