
声明
此文是我 Angular 系列文章中的一篇。在 Angular 系列文章中,我尽可能的用简单的语言对 Angular 的许多概念进行总结,分析了一些 API 的设计的原因,希望这些东西能对读者有所帮助。
正文
在Angular中,常常会看到在 AppModule 中调用某个模块的 forRoot 方法。其中最常见的应该就是 RouterModule.forRoot()。但是 forRoot 的作用是什么?什么时候要自己编写 forRoot?读完本文,相信你会有一个答案。
forRoot 解决的问题
forRoot 方法主要是为了解决依赖注入(DI)实例生成的问题。在 《 Angular 模块基础教程 》中曾经提到,若一个带服务的模块被反复在特性模块中导入,且此特性模块被惰性加载,那么在这个模块中就会单独生成一个依赖注入的实例。这在某些场景下可能不是你想要的。
一个 CountService
假如你想创建一个全局计数的 CountService,然后你又采用惰性加载的方式来加载包含此 service 的模块,那么由于惰性加载的模块拥有的 CountService 实例,和正常加载的模块所拥有的 CountService 实例不相同。那么就可能导致计数的值出现不一致。Chris House 写了这样一个 Demo ,可以帮助我们更好地理解这个场景。
可以清楚的看到惰性加载的模块和主模块依赖注入的并不是同一个实例,因此,累计计数的结果不一致。在这种场景下,就要使用 forRoot 来生成全局唯一的 service。
forRoot 如何写
若你想让某个 CoreModule 中的 services ,够在应用程序的全局生命周期中使用。那么可以给 CoreModule 添加一个名为 forRoot 的静态方法。并返回一个 ModuleWithProviders 对象。

然后你只要在应用的 AppModule 中 imports 这个 CoreModule,就能在应用生命周期的全局,无论子模块是否是惰性加载,共用这个全局 service 实例。
除此之外!
当然对于不是惰性加载的模块,多次重复导入相同的服务同样也是不可取的。这是因为,当我们在多个子模块/特性模块中导入了相同的服务后,就会导致这个服务被注册许多次,无法保证这个服务实例全局唯一!
最佳实践
对于本身包含一系列服务的模块,并且需要在整个应用生命周期保持单例模式。我们最好把它们放在 forRoot 方法中,并在 forChild 方法中单纯提供组件或者指令等其他元数据。
相关阅读
我在 Angular 模块漫谈 中对导入第三方模块的方法进行了全面的总结。这里也再次提到了 forRoot 与 forChild 的区别。
高级教程
参考链接
When to use Angular’s forRoot() method
写的很好,受教了,感谢
能够帮到你很高兴