Angular Service Modules是否仍然需要?
Angular Service Modules是否仍然需要?
在Angular文档中,列出了可以实现的功能模块的类型,其中之一是服务模块。在早期版本的Angular中,您需要创建您的服务并将其列在服务NgModule的providers数组中。然后,使用该NgModule的应用程序将导入并在应用程序根注入器中提供该服务。
@Injectable()
export class MyService {}
@NgModule({
providers: [MyService]
})
export class MyServicesModule {}
@NgModule({
imports: [MyServicesModule]
})
export class AppModule {}
最新的Angular推荐使用@Injectable注解,您不再需要在providers定义中列出它。
@Injectable({ providedIn: 'root'})
export class MyService {}
因此,是否有必要创建服务模块?您只需使用上述注解在根注入器中创建要提供的服务,并直接导入和注入服务类即可。
在Angular中,一个单例服务是指通过providedIn: 'root'
来提供的服务,以便利用树摇优化机制。单例服务的位置有以下几种情况:
- 如果一个服务文件位于特性模块的services文件夹中,可以将服务文件放在这里。
- 对于一些不属于特定特性模块的服务(例如多个模块都使用的日志服务),可以将服务组织到一个没有core.module.ts的核心文件夹中。详情请参考Angular的编码风格指南。
然而,根据具体情况,如果你在使用ngrx store或类似的库,可能需要一个CoreModule或一些ServiceModule来导入这些文件(ngrx模块)。详情请参考Angular v6的编码风格指南。
P.S. 如果要在整个应用中共享东西,可以考虑使用SharedModule来共享管道、指令和组件,但不适用于服务。在shared.module.ts中,可能没有providers属性的装饰器。详情请参考Angular的SharedModule文档。
总结一下,Angular文档推荐将所有服务设为单例且可树摇优化;服务可以放在以下三个位置:特性模块的services文件夹、核心模块/服务模块(特别是使用ngrx的情况)、专门用于组织服务的核心文件夹。
相关文档和参考资料:
- https://angular.io/guide/singleton-services
- https://angular.io/guide/providers
- https://angular.io/guide/router
- https://angular.io/guide/lazy-loading-ngmodules
- https://v6.angular.io/guide/styleguide
- https://stackoverflow.com/questions/42695931/42696386#42696386
Angular Service Modules是否仍然需要?
在使用懒加载模块时,如果模块中的组件只提供特定的服务,那么就需要一个服务模块。
你不能将服务提供给与该模块的组件注入的模块相同的模块中。
所以假设你有一个MyLazyFeatureModule
:
({ imports: [ ], providers: [ ], declarations: [ MyFeatureComponent ], exports: [ ], }) export class MyLazyFeatureModule { }
还有一个只包含与你的功能相关逻辑的服务,那么你不能这样做:
Injectable({ providedIn: MyLazyFeatureModule}) export class MyFeatureService {}
你会得到一个循环依赖的错误!
要解决这个问题,你需要创建一个特定的服务模块并将其导入到功能模块中:
({ imports: [ ], providers: [ ], declarations: [ ], exports: [ ], }) export class MyLazyFeatureServiceModule { }
Injectable({ providedIn: MyFeatureServiceModule}) export class MyFeatureService {}
({ imports: [ MyLazyFeatureServiceModule ], providers: [ ], declarations: [ MyFeatureComponent ], exports: [ ], }) export class MyLazyFeatureModule { }
请查看这篇文章 (three shakable providers why, how and cycles),由Manfred Steyer详细解释了为什么会出现循环依赖的问题。
除此之外,如果你只在根目录下提供服务,那么可能不需要服务模块。你也可以创建一个核心模块来集中所有的服务。这取决于你的需求。
如果不打算导入服务模块,那么我认为没有必要创建一个模块,这似乎是多余的。你能解释一下你所说的核心模块是什么意思吗?
你必须将服务模块导入到功能模块中。我将在我的回答中添加一个结构概述,或许这样会更清楚一些。
更新了我的回答,希望现在更清楚了为什么需要这个服务模块。
谢谢你的帮助。我试着访问你提供的链接,但是我不太理解它想要传达的意思。上面的MyFeatureModule是打算在懒加载的上下文中使用的吗?如果是这样,也许更新模块的名称来包含“Lazy”这个词会更好。你能解释一下你在第一个例子中提到的循环是指什么吗?
是的,大部分情况下都是这样的用例。你有一个懒加载的功能模块,并且你希望将服务限定在该范围内,以便服务只被捆绑在懒加载模块中,而不是主应用程序中。如果你想实现这一点,你需要添加一个服务模块。
好的,非常感谢!我理解你在谈论作用域的问题。但是对于循环依赖的参考,我仍然感到困惑!
我们可以创建一个服务模块。我知道我们可以在模块的'providers'数组中注册一个服务({}),或者在({})中注册一个服务。创建一个名为MyFeatureServiceModule的服务模块意味着什么?
循环发生的原因是,当编译器尝试创建模块时,它会遍历组件并创建组件中注入的服务的实例(如果不存在)。当编译器遇到一个服务,它的providedIn与它当前正在尝试创建的模块相同时,编译器会进入循环,因为它需要创建服务以创建模块,但也需要模块来创建服务。
服务模块是一种将服务分组到自己的功能相关模块中的模式,使得路由模块更易读,因为提供者列表不会那么长。这里的问题是,随着树摇动的提供者引入(providedIn声明),这种模式是否已经过时,或者是否仍然有用的用例。
如果我有一个名为'myService.ts'的服务,其中包含名为'myServiceClass'的类,并且想要将实例注入到名为'myFeatureModule.module.ts'的功能模块中,其中包含名为'myFeatureModule'的类。我不能像这样注册'myService.ts':({ providedIn: 'myFeatureModule' }),就像我们使用({ providedIn: 'root' })一样吗?我认为我们也可以像这样做。基本上,'providedIn'只是注册服务的一种简便方式。 stackoverflow.com/questions/50848357/…
没有人说过你不能只使用提供者列表,或者必须使用服务模块。树摇动的声明(providedIn)不仅仅是一个简化,而是为了使未使用的代码部分的树摇动更加高效。在官方的Angular文档和我在回答中提供的链接中有大量的解释,如果你想要了解更多的话。所以选择哪种方式取决于具体的用例...
非常好的信息。现在更加清晰了。我的唯一建议是更新你的示例模块类名称,以包含"Lazy"一词,以提高其他人的理解能力。