官方认为组件不该该直接获取或保存数据, 它们应该聚焦于展现数据,而把数据访问的职责委托给某个服务。而服务就充当着数据访问,逻辑处理的功能。把组件和服务区分开,以提升模块性和复用性。经过把组件中和视图有关的功能与其余类型的处理分离开,可让组件类更加精简、高效,这是官方的一些定义。很是认同,以我粗鄙的我的开发经验来看,现实开发中并不能彻底的把组件和服务区分开来。并无作到为组件提供专门的服务,或者说把逻辑处理都放在服务,组件只展现数据。一个模块一般有许多组件,咱们的每一个业务模块中只存在一个服务,将模块中的数据访问,数据处理判断,通用的方法放在服务中而已。组件中仍是会有一些数据的判断,页面的展现逻辑等。固然咱们也有服务提供给各个组件使用,一些通用的服务 好比 httpService logService uiServic 等等。可能我说的是针对于业务上等服务没法彻底剥离吧。
bootstrap
1.依赖注入
-
注入器是主要的机制。Angular 会在启动过程当中为你建立全应用级注入器以及所需的其它注入器。你不用本身建立注入器。app
-
该注入器会建立依赖、维护一个容器来管理这些依赖,并尽量复用它们。ide
-
提供商是一个对象,用来告诉注入器应该如何获取或建立依赖。函数
2.服务提供商
咱们使用命令ng g s servicename建立一个服务,在新建的服务中咱们能够看到@Injectable()装饰器,它把这个类标记为依赖注入系统的参与者之一。组件中如何使用服务呢,必须将服务依赖注入系统、组件或者模块,才可以使用服务。咱们能够用注册提供商和根注入器实现。性能
该服务自己是 CLI 建立的一个类,而且加上了 @Injectable()
装饰器。默认状况下,该装饰器是用 providedIn
属性进行配置的,它会为该服务建立一个提供商。在这个例子中,providedIn: 'root'
指定 Angular 应该在根注入器中提供该服务,从而实现根注入器将服务注入,它就在整个应用程序中可用了。学习
testService.tsui
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root', }) export class TestService { }
也能够指定某个服务只有在特定的模块中提供,相似于一个业务模块中专属于这个模块的服务,只会应用于此模块中,咱们就能够这么作。this
import { Injectable } from '@angular/core'; import { TestModule } from './test.module'; @Injectable({ providedIn: TestModule, }) export class TestService { }
orspa
import { NgModule } from '@angular/core'; import { TestService } from './test.service'; @NgModule({ providers: [TestService], }) export class TestModule { }
也能够直接在某个组件中注入服务。code
@Component({ /* . . . */ providers: [TestService] })
3.服务的做用域
为何一个服务而已,有多种注入的方法有什么区别吗,有。这就在于这个服务做用于哪里,用于限定服务使用的界限。当咱们将某个服务根注入意味着在整个应用中均可以使用,注入于某个模块,只能应用于某个模块,注入于组件中,只应用于此组件。咱们根据对服务的功能定义,来选择合适的注入方式,以提升性能。
4.单例服务
提供单例服务的方法:
-
把
@Injectable()
的providedIn
属性声明为root
。
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root', }) export class TestService { }
-
把该服务包含在
AppModule
或某个只会被AppModule
导入的模块中。
@NgModule({ ... providers: [TestService], ... })
forRoot() 模式
若是模块同时定义了 providers (服务),当你在多个特性模块中加载此模块时,这些服务就会被注册在多个地方。这会致使出现多个服务实例,而且该服务的行为再也不像单例同样 。有多种方式来防止这种现象:
- 用 providedIn 语法代替在模块中注册服务的方式。
- 把你的服务分离到它们本身的模块中。
- 在模块中分别定义 forRoot() 和 forChild() 方法。
使用 forRoot() 来把提供商从该模块中分离出去,这样你就能在根模块中导入该模块时带上 providers ,而且在子模块中导入它时不带 providers。
ps: RouterModule
没有 forRoot()
GreetingModule.ts
static forRoot(config: TestServiceConfig): ModuleWithProviders { return { ngModule: GreetingModule, providers: [ {provide: TestServiceConfig, useValue: config } ] }; }
导入 GreetingModule,并只在 AppModule 中调用一次它的 forRoot() 方法。像这样注册它一次就能够防止出现多个实例。
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; /* App Root */ import { AppComponent } from './app.component'; /* Feature Modules */ import { ContactModule } from './contact/contact.module'; import { GreetingModule } from './greeting/greeting.module'; /* Routing Module */ import { AppRoutingModule } from './app-routing.module'; @NgModule({ imports: [ BrowserModule, ContactModule, GreetingModule.forRoot({userName: 'Miss Marple'}), AppRoutingModule ], declarations: [ AppComponent ], bootstrap: [AppComponent] }) export class AppModule { }
工做原理:
在 GreetingModule.ts
中,咱们能够看到,添加一个用于配置 UserService
的 forRoot()
方法,可选的注入 TestServiceConfig
扩展了 TestService
。若是 TestServiceConfig
存在,就从这个配置中设置用户名。
test.service.ts (constructor)
content_copyconstructor(@Optional() config: Test) { if (config) { this._userName = config.userName; } }ServiceConfig
如何有效的防止重复导入:
只有根模块 AppModule 才能导入 GreetingModule。若是一个惰性加载模块也导入了它, 该应用就会为服务生成多个实例。
为 GreetingModule
添加构造函数,该构造函数要求 Angular 把 GreetingModule 注入它本身。 若是 Angular 在当前注入器中查找 GreetingModule,此次注入就会致使死循环,可是 @SkipSelf() 装饰器的意思是 "在注入器树中层次高于个人祖先注入器中查找 GreetingModule。",能有效的防止重复的导入。
greeting.module.ts
import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; import { CommonModule } from '@angular/common'; import { GreetingComponent } from './greeting.component'; import { UserServiceConfig } from './user.service'; @NgModule({ imports: [ CommonModule ], declarations: [ GreetingComponent ], exports: [ GreetingComponent ] }) export class GreetingModule { constructor (@Optional() @SkipSelf() parentModule: GreetingModule) { if (parentModule) { throw new Error( 'GreetingModule is already loaded. Import it in the AppModule only'); } } static forRoot(config: UserServiceConfig): ModuleWithProviders { return { ngModule: GreetingModule, providers: [ {provide: UserServiceConfig, useValue: config } ] }; } }
此随笔乃本人学习工做记录,若有疑问欢迎在下面评论,转载请标明出处。
若是对您有帮助请动动鼠标右下方给我来个赞,您的支持是我最大的动力。