Angular Service(服務)

      官方認爲組件不該該直接獲取或保存數據, 它們應該聚焦於展現數據,而把數據訪問的職責委託給某個服務。而服務就充當着數據訪問,邏輯處理的功能。把組件和服務區分開,以提升模塊性和複用性。經過把組件中和視圖有關的功能與其餘類型的處理分離開,可讓組件類更加精簡、高效,這是官方的一些定義。很是認同,以我粗鄙的我的開發經驗來看,現實開發中並不能徹底的把組件和服務區分開來。並無作到爲組件提供專門的服務,或者說把邏輯處理都放在服務,組件只展現數據。一個模塊一般有許多組件,咱們的每一個業務模塊中只存在一個服務,將模塊中的數據訪問,數據處理判斷,通用的方法放在服務中而已。組件中仍是會有一些數據的判斷,頁面的展現邏輯等。固然咱們也有服務提供給各個組件使用,一些通用的服務 好比 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 }
      ]
    };
  }
}

 

此隨筆乃本人學習工做記錄,若有疑問歡迎在下面評論,轉載請標明出處。

若是對您有幫助請動動鼠標右下方給我來個贊,您的支持是我最大的動力。

相關文章
相關標籤/搜索