官方認爲組件不該該直接獲取或保存數據, 它們應該聚焦於展現數據,而把數據訪問的職責委託給某個服務。而服務就充當着數據訪問,邏輯處理的功能。把組件和服務區分開,以提升模塊性和複用性。經過把組件中和視圖有關的功能與其餘類型的處理分離開,可讓組件類更加精簡、高效,這是官方的一些定義。很是認同,以我粗鄙的我的開發經驗來看,現實開發中並不能徹底的把組件和服務區分開來。並無作到爲組件提供專門的服務,或者說把邏輯處理都放在服務,組件只展現數據。一個模塊一般有許多組件,咱們的每一個業務模塊中只存在一個服務,將模塊中的數據訪問,數據處理判斷,通用的方法放在服務中而已。組件中仍是會有一些數據的判斷,頁面的展現邏輯等。固然咱們也有服務提供給各個組件使用,一些通用的服務 好比 httpService logService uiServic 等等。可能我說的是針對於業務上等服務沒法徹底剝離吧。
bootstrap
注入器是主要的機制。Angular 會在啓動過程當中爲你建立全應用級注入器以及所需的其它注入器。你不用本身建立注入器。app
該注入器會建立依賴、維護一個容器來管理這些依賴,並儘量複用它們。ide
提供商是一個對象,用來告訴注入器應該如何獲取或建立依賴。函數
咱們使用命令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] })
爲何一個服務而已,有多種注入的方法有什麼區別嗎,有。這就在於這個服務做用於哪裏,用於限定服務使用的界限。當咱們將某個服務根注入意味着在整個應用中均可以使用,注入於某個模塊,只能應用於某個模塊,注入於組件中,只應用於此組件。咱們根據對服務的功能定義,來選擇合適的注入方式,以提升性能。
提供單例服務的方法:
把 @Injectable()
的 providedIn
屬性聲明爲 root
。
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root', }) export class TestService { }
把該服務包含在 AppModule
或某個只會被 AppModule
導入的模塊中。
@NgModule({
...
providers: [TestService],
...
})
forRoot() 模式
若是模塊同時定義了 providers (服務),當你在多個特性模塊中加載此模塊時,這些服務就會被註冊在多個地方。這會致使出現多個服務實例,而且該服務的行爲再也不像單例同樣 。有多種方式來防止這種現象:
使用 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 } ] }; } }
此隨筆乃本人學習工做記錄,若有疑問歡迎在下面評論,轉載請標明出處。
若是對您有幫助請動動鼠標右下方給我來個贊,您的支持是我最大的動力。