Angular9 服務(wù)與 DI 簡介

2020-06-28 17:06 更新

服務(wù)與依賴注入簡介

服務(wù)是一個廣義的概念,它包括應(yīng)用所需的任何值、函數(shù)或特性。狹義的服務(wù)是一個明確定義了用途的類。它應(yīng)該做,并做好一些具體的事。

Angular 把組件和服務(wù)區(qū)分開,以提高模塊性和復(fù)用性。 通過把組件中和視圖有關(guān)的功能與其它類型的處理分離開,你可以讓組件類更加精簡、高效。

理想情況下,組件的工作只管用戶體驗,而不用顧及其它。 它應(yīng)該提供用于數(shù)據(jù)綁定的屬性和方法,以便作為視圖(由模板渲染)和應(yīng)用邏輯(通常包含一些模型的概念)的中介者。

組件應(yīng)該把諸如從服務(wù)器獲取數(shù)據(jù)、驗證用戶輸入或直接往控制臺中寫日志等工作委托給各種服務(wù)。通過把各種處理任務(wù)定義到可注入的服務(wù)類中,你可以讓它被任何組件使用。 通過在不同的環(huán)境中注入同一種服務(wù)的不同提供者,你還可以讓你的應(yīng)用更具適應(yīng)性。

Angular 不會強迫您遵循這些原則。Angular 只會通過依賴注入來幫您更容易地將應(yīng)用邏輯分解為服務(wù),并讓這些服務(wù)可用于各個組件中。

應(yīng)用示例

以下示例,用于將日志記錄到瀏覽器的控制臺。

export class Logger {
  log(msg: any)   { console.log(msg); }
  error(msg: any) { console.error(msg); }
  warn(msg: any)  { console.warn(msg); }
}

服務(wù)也可以依賴其它服務(wù)。比如,這里的 HeroService 就依賴于 Logger 服務(wù),它還用 BackendService 來獲取英雄數(shù)據(jù)。BackendService 還可能再轉(zhuǎn)而依賴 HttpClient 服務(wù)來從服務(wù)器異步獲取英雄列表。

export class HeroService {
  private heroes: Hero[] = [];


  constructor(
    private backend: BackendService,
    private logger: Logger) { }


  getHeroes() {
    this.backend.getAll(Hero).then( (heroes: Hero[]) => {
      this.logger.log(`Fetched ${heroes.length} heroes.`);
      this.heroes.push(...heroes); // fill cache
    });
    return this.heroes;
  }
}

依賴注入

DI 被融入 Angular 框架中,用于在任何地方給新建的組件提供服務(wù)或所需的其它東西。 組件是服務(wù)的消費者,也就是說,你可以把一個服務(wù)注入到組件中,讓組件類得以訪問該服務(wù)類。

在 Angular 中,要把一個類定義為服務(wù),就要用 @Injectable() 裝飾器來提供元數(shù)據(jù),以便讓 Angular 可以把它作為依賴注入到組件中。 同樣,也要使用 @Injectable() 裝飾器來表明一個組件或其它類(比如另一個服務(wù)、管道或 NgModule)擁有一個依賴。

  • 注入器是主要的機制。Angular 會在啟動過程中為你創(chuàng)建全應(yīng)用級注入器以及所需的其它注入器。你不用自己創(chuàng)建注入器。

  • 該注入器會創(chuàng)建依賴、維護一個容器來管理這些依賴,并盡可能復(fù)用它們。

  • 提供者是一個對象,用來告訴注入器應(yīng)該如何獲取或創(chuàng)建依賴。

你的應(yīng)用中所需的任何依賴,都必須使用該應(yīng)用的注入器來注冊一個提供者,以便注入器可以使用這個提供者來創(chuàng)建新實例。 對于服務(wù),該提供者通常就是服務(wù)類本身。

注:
- 依賴不一定是服務(wù),它也有可能是函數(shù)或者值。

當 Angular 創(chuàng)建組件類的新實例時,它會通過查看該組件類的構(gòu)造函數(shù),來決定該組件依賴哪些服務(wù)或其它依賴項。 比如 HeroListComponent 的構(gòu)造函數(shù)中需要 HeroService:

constructor(private service: HeroService) { }

當 Angular 發(fā)現(xiàn)某個組件依賴某個服務(wù)時,它會首先檢查是否該注入器中已經(jīng)有了那個服務(wù)的任何現(xiàn)有實例。如果所請求的服務(wù)尚不存在,注入器就會使用以前注冊的服務(wù)提供者來制作一個,并把它加入注入器中,然后把該服務(wù)返回給 Angular。

當所有請求的服務(wù)已解析并返回時,Angular 可以用這些服務(wù)實例為參數(shù),調(diào)用該組件的構(gòu)造函數(shù)。

HeroService 的注入過程如下所示:

提供服務(wù)

對于要用到的任何服務(wù),您必須至少注冊一個提供者。服務(wù)可以在自己的元數(shù)據(jù)中把自己注冊為提供者,這樣可以讓自己隨處可用。或者,您也可以為特定的模塊或組件注冊提供者。要注冊提供者,就要在服務(wù)的 @Injectable() 裝飾器中提供它的元數(shù)據(jù),或者在 @NgModule()@Component() 的元數(shù)據(jù)中。

  • 默認情況下,Angular CLI 的 ng generate service 命令會在 @Injectable() 裝飾器中提供元數(shù)據(jù)來把它注冊到根注入器中。本教程就用這種方法注冊了 HeroService 的提供者:

@Injectable({
  providedIn: 'root',
})

當你在根一級提供服務(wù)時,Angular 會為 HeroService 創(chuàng)建一個單一的共享實例,并且把它注入到任何想要它的類中。這種在 @Injectable 元數(shù)據(jù)中注冊提供者的方式還讓 Angular 能夠通過移除那些從未被用過的服務(wù)來優(yōu)化大小。

  • 當你使用特定的 NgModule 注冊提供者時,該服務(wù)的同一個實例將會對該 NgModule 中的所有組件可用。要想在這一層注冊,請用 @NgModule() 裝飾器中的 providers 屬性:

@NgModule({
  providers: [
   BackendService,
   Logger
 ],
 ...
})

  • 當您在組件級注冊提供者時,您會為該組件的每一個新實例提供該服務(wù)的一個新實例。 要在組件級注冊,就要在 @Component() 元數(shù)據(jù)的 providers 屬性中注冊服務(wù)提供者。

@Component({
  selector:    'app-hero-list',
  templateUrl: './hero-list.component.html',
  providers:  [ HeroService ]
})
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號