首页 > 解决方案 > Angular DI - useFactory - Provider:有没有办法在本地状态更新时第二次调用 Provider Factory 函数?

问题描述

场景如下:

1. App 有根模块,它的构造函数解析一个 Promise 并返回一个常量。

@NgModule({
    ....,
    providers : [
    ...
    { 
      provide: SAMPLE_INJECTOR_TOKEN,
      useFactory: sampleFactoryFn(SAMPLE_GLOBAL_CONSTANT.DATA)
    }
       ]
})
export class AppModule {
 constructor() {
  // To be clear: This code runs on window.onLoad(). window argument is actually window object
  setupPromiseAPI(window).then(data => {
   SAMPLE_GLOBAL_CONSTANT.DATA = data; // Once promise resolves this gets expected value. [ Step 3 ]
  }).catch({
      ...
  })

}

2. 由于这个值是一个对象,而且它在运行时可用,我使用“useFactory”创建了一个注入令牌并在模块级别注册。

// Injector Token    
export SAMPLE_INJECTOR_TOKEN = new InjectionToken<CustomDataType>('SampleInjectorToken');

// Factory Function
export function sampleFactoryFn(data: CustomDataType) {
       return (/* No deps to be passed */): CustomDataType => data; // simply return what ever it received.
            }

3. 我创建了一个全局常量,初始化为 null 并作为参数传递给工厂函数,使用哪个 angular 构造 Injector Token 并在引导时分配值 null(初始状态)。

export const SAMPLE_GLOBAL_CONSTANT = {
    DATA: null // Initial State
}

4. 当 promise 从第 1 步解决时,我从 Promise 捕获返回的常量值并分配给这个声明的全局常量,作为它的常量,显然它正在更新并通过应用程序可用。

此外,角度文档指出 useFactory 提供程序会懒惰地创建它的值,我理解它会在注入时创建。如果是这样,当代码注入我的注入令牌时,全局常量就会更新。注入器令牌仍然为空。

Q1。有没有办法使用更新的本地状态调用提供程序工厂函数,以便我的注入器令牌将收到价值?

Q2。由于我使用全局常量,它使代码工作,但它不是松散耦合的,这也使得单元测试变得困难。是否有任何替代方法可以使用接收到的常量并在代码中使用它,以便松散耦合?

标签: angulardependency-injectionangular-di

解决方案


我解决的一种方法是使用来自 RxJS 的 Replay Subject。首先,这是一个封装在 Promise 中的 postMessage 服务。因此,一旦(从另一个应用程序)发送消息并解决了承诺(在使用应用程序中),就必须有一种方法来保存发送数据以在整个应用程序中使用它。

使用缓冲区值为 1 的重播主题,这意味着将最近的一个值重播到订阅,一旦上述场景得到解决,就会产生最后捕获的值。

然后将获得的数据传递给订阅中的 Angular 服务,使其在整个应用程序中可用。

现在,这使得 Angular 服务中的所需数据而不是全局常量中的数据,这使得单元测试变得容易。

注意: Factory Provider 无法解决这种情况,因为 angular 会在启动发生之前尝试解决,默认为初始化值(在我的情况下,它是 null)。所以这行不通。

为什么不异步主题?

由于异步主题仅在完成信号后被触发,并且我正在解决的业务案例在声明完成信号之前确实有中间工作要做。它没有解决目的。


推荐阅读