处理 DI 生命周期和服务类中的缓存数据

问题描述 投票:0回答:1

我的 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
实例时都会重新创建取决于它的页面)?

angular typescript dependency-injection
1个回答
0
投票

您可以在导航端使用路由器的

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();
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.