解决由于 APP_INITIALIZER 引起的循环依赖

Solving cyclic dependency due to APP_INITIALIZER

我有一个加载 AngularFirestore 的服务 AuthenticationService。该服务已在 RootComponent 中加载。 RootComponent 中的所有应用程序模块都是延迟加载的(它有主要的 router-outlet)。现在有很多子模块也加载AngularFirestore.

我必须确保 AuthenticationService 在加载组件和模块之前被初始化(异步的东西),所以我把它放在 APP_INITIALIZER 提供程序中。这导致 cyclic-dependency Cannot instantiate cyclic dependency! AngularFirestore.

如果我不把它放在 APP_INITIALIZER 中,它可以工作,但应用程序运行时没有 AuthenticationService 被初始化。

有办法解决这个问题吗? (除了在所有组件中添加auth.initialize()

应用树:

AppComponent -> RootComponent(AuthenticationService) -> All Submodules(AuthenticationService, AngularFirestore)
// constructor of AuthenticationService
constructor(
    private auth : AngularFireAuth,
    private remoteconfig : AngularFireRemoteConfig,
    private keepalive: Keepalive,
    private idle: Idle, 
    private toast : ToastService,
    private router : Router,
    private fs : AngularFirestore,
    private http : HttpClient,
)
// providers in app.module.ts
{
  provide: APP_INITIALIZER,
  multi: true,
  useFactory: authFactory,
  deps: [
    AuthenticationService
  ]
}
// Factory for APP_INITIALIZER
export function authFactory(
  auth : AuthenticationService
) {
  return () : Promise<any> => auth.initialize();
}

此致!

因此,在浏览了大量 github 评论和不相关的 SO 问题后,我想出了一个解决方案,我在 Github 评论中浏览了一个不相关的问题。

TLDR:通过为 AngularFirestore 或整个应用程序创建新服务来进行注入。我选择了后者。

理解问题:

据我了解,问题是因为我的 AuthenticationService 加载了 AngularFirestore 并使其成为依赖树的一部分。现在 AuthenticationServiceAngularFirestore 的任何后续注入都会产生循环依赖,因为注入 AuthenticationService 会使 AngularFirestore 成为依赖树的一部分,并且当我注入 AngularFirestore 之后它创建了两次 AngularFirestore 注入。因此错误。我可能完全错了,但我认为这就是问题所在。

解法:

AngularFirestore 导入创建服务。我认为,这会将它从依赖树中移出并将其作为服务注入,使其可以用于任何后续注入 AngularFirestore safe.

// appfirestoreservice.ts
import { Injectable } from '@angular/core';
import { AngularFirestore } from '@angular/fire/firestore';

@Injectable({
  providedIn: 'root'
})
export class AppFirestoreService {
  
  public fs : AngularFirestore;
  public readonly collection = this._fs.collection;
  public readonly doc = this._fs.doc;
  public readonly createId = this._fs.createId;

  constructor(
    private _fs : AngularFirestore,
  ) {
    this.fs = _fs;
  }
}
// App Initializer in AppModule
{
  provide: APP_INITIALIZER,
  multi: true,
  useFactory: initFactory,
  deps: [
    AppServiceInitializerService,
    RemoteConfigService,
    AuthenticationService,
  ]
},

对于我的情况,我必须创建一个服务来加载 RemoteConfigServiceAuthenticationService,因为它们必须一个接一个地初始化。

此致!