服务在APP_INITIALIZER之后实例化两次

时间:2018-11-09 12:56:03

标签: angular dependency-injection singleton angular6

问题是:我需要进行http调用并存储生成动态路由所需的对象。因此,我正在利用APP_INITIALIZER。

// app.module.ts
import { ApplicationService } from './application.service';


providers: [
  ApplicationService,
  { 
  provide: APP_INITIALIZER, useFactory: appServiceFactory, deps: 
  [Injector, ApplicationService], multi: true 
  },
],

function appServiceFactory(injector: Injector, appService: ApplicationService): Function {
  return () => {
    return appService.loadApplication().then((app: Application) => {
      /custom logic
      });
    });
  };
}


// application.service.ts
@Injectable({
  providedIn: 'root'
})

// navigation.component.ts
import { ApplicationService } from './application.service';

export class NavigationComponent implements OnInit {

    constructor(private _applicationService: ApplicationService) {
  }

}

但是在navigation.component内部,applicationservice再次被初始化。我敢肯定,因为如果我记录或放置调试器语句,则该服务的Construct()方法将被调用两次。

为什么要重新实例化带有providedIn: root的服务为单例?

4 个答案:

答案 0 :(得分:3)

这样做的原因是,一旦将Router包含在APP_INITIALIZER工厂的依赖项中,您就会得到循环依赖项(https://github.com/angular/angular/blob/4c2ce4e8ba4c5ac5ce8754d67bc6603eaad4564a/packages/router/src/router_module.ts#L61-L64)。

ApplicationService
       |
    TestService
       |
     Router
       |
  ApplicationRef
       |
ApplicationInitStatus
       |
 APP_INITIALIZER
       |
ApplicationService

要解决此问题,您可以延迟获取路由器:

export class TestService {

  get router() {
    return this.injector.get(Router)
  }

  constructor(private _http: HttpClient, private injector: Injector ) {
  }
}

Forked Stackblitz

答案 1 :(得分:1)

根据您的解释,即您在providedIn: root中添加了application.service.ts,这意味着它将被添加到根模块(即Appmodule.ts)中,并再次添加到Appmodule.ts中在provider数组中,您要添加ApplicationService

从此Blog开始,其状态

  

“现在有一种推荐的新方式可以直接注册提供商   在@Injectable()装饰器中,使用新的providerIn   属性。它接受“根”作为值或您的任何模块   应用。当您使用“ root”时,您的注射剂将被注册   作为应用程序中的单例,您无需将其添加到   根模块的提供者。同样,如果使用providerIn:   UsersModule,注射剂已注册为   UsersModule,而无需将其添加到模块的提供程序中。”

这正在创建要重新实例化的服务

编辑1: 另一件事要检查的是, 1.在开发模式或生产模式下,您如何称呼此服务,如果是开发模式,则该服务将被调用两次

  

如果您在开发模式下运行,它将在以下位置运行该功能   至少两次。因为在开发模式下会进行检查,更改,然后   重新检查以验证,其中生产模式仅进行第一次检查,   假设您已经完成了质量保证并解决了所有价值   获取更改后的检查。

Source

尝试在产品模式下检查并验证。.

答案 2 :(得分:0)

发现了问题:这是由于路由器,ApplicationApplication中注入的服务需要将其作为依赖项。

请参阅示例: https://stackblitz.com/edit/angular-xwyugy

将Router从ApplicationService中删除后,双重实例化消失了。

不明白为什么,所以我将等待更好的批准答案。

答案 3 :(得分:0)

我还面临一个问题,即我的服务被实例化了两次,并且从日志中看到的情况来看,从config.service.ts文件中调用了一个构造函数,而从config.service.js文件中调用了一个构造函数(请注意扩展名的区别)。发生这样的错误,我是这样导入服务的:

import { ConfigService } from '../config/config.service.js';

代替:

import { ConfigService } from '../config/config.service';

将其更改为正确的导入即可解决此问题。