Angular 依赖注入的学习笔记
Angular官方文檔
Specifying a provider token
If you specify the service class as the provider token, the default behavior is for the injector to instantiate that class with new.
In the following example, the Logger class provides a Logger instance.
providers: [Logger]
NgModule的providers區域里,指定provider token. 如果將一個服務類直接指定成provider token,默認的行為就是,injector直接用new來初始化那個類。
上面的例子,會觸發Logger的構造函數。等價于:
[{ provide: Logger, useClass: Logger }]
這個完整的聲明在Angular官方文檔里稱為expanded provider configuration, 是一個包含兩個屬性的對象。
- The provide property holds the token that serves as the key for both locating a dependency value and configuring the injector.
provide屬性包含一個token,用于定位一個dependency value和配置injector.
- The second property is a provider definition object, which tells the injector how to create the dependency value. The provider-definition key can be useClass, as in the example. It can also be useExisting, useValue, or useFactory. Each of these keys provides a different type of dependency, as discussed below.
第二個屬性是一個provider定義對象,告訴injector如何創建dependency value. 這個定義可以是useClass,useExisting,useValue,或者useFactory.
一些例子:
[{ provide: Logger, useClass: BetterLogger }]
當使用Logger token時,injector返回BetterLogger的實例。
Aliasing class providers
To alias a class provider, specify the alias and the class provider in the providers array with the useExisting property.
In the following example, the injector injects the singleton instance of NewLogger when the component asks for either the new or the old logger. In this way, OldLogger is an alias for NewLogger.
下列的配置,會導致Component需要使用OldLogger時,會返回NewLogger的singleton實例。當然,如果請求NewLogger,亦會返回NewLogger實例。因此這種情形下,OldLogger是NewLogger語義層面的alias.
[ NewLogger,// Alias OldLogger w/ reference to NewLogger{ provide: OldLogger, useExisting: NewLogger}]如果使用如下命令行創建 service:
ng generate service User
自動生成的代碼:
import { Injectable } from '@angular/core';@Injectable({providedIn: 'root', }) export class UserService { }現在,你就可以在應用中到處注入 UserService 了。
該服務本身是 CLI 創建的一個類,并且加上了 @Injectable() 裝飾器。默認情況下,該裝飾器是用 providedIn 屬性進行配置的,它會為該服務創建一個提供者。在這個例子中,providedIn: ‘root’ 指定 Angular 應該在根注入器中提供該服務。
當你把服務提供者添加到應用的根注入器中時,它就在整個應用程序中可用了。 另外,這些服務提供者也同樣對整個應用中的類是可用的 —— 只要它們有供查找用的服務令牌。
你應該始終在根注入器中提供這些服務 —— 除非你希望該服務只有在消費方要導入特定的 @NgModule 時才生效。
也可以規定某個服務只有在特定的 @NgModule 中提供。比如,如果你希望只有當消費方導入了你創建的 UserModule 時才讓 UserService 在應用中生效,那就可以指定該服務要在該模塊中提供:
import { Injectable } from '@angular/core'; import { UserModule } from './user.module';@Injectable({providedIn: UserModule, }) export class UserService { }上面的例子展示的就是在模塊中提供服務的首選方式。之所以推薦該方式,是因為當沒有人注入它時,該服務就可以被搖樹優化掉。如果沒辦法指定哪個模塊該提供這個服務,你也可以在那個模塊中為該服務聲明一個提供者。
服務是一個廣義的概念,它包括應用所需的任何值、函數或特性。狹義的服務是一個明確定義了用途的類。它應該做一些具體的事,并做好。
Angular 把組件和服務區分開,以提高模塊性和復用性。 通過把組件中和視圖有關的功能與其它類型的處理分離開,你可以讓組件類更加精簡、高效。
理想情況下,組件的工作只管用戶體驗,而不用顧及其它。 它應該提供用于數據綁定的屬性和方法,以便作為視圖(由模板渲染)和應用邏輯(通常包含一些模型的概念)的中介者。
組件應該把諸如從服務器獲取數據、驗證用戶輸入或直接往控制臺中寫日志等工作委托給各種服務。通過把各種處理任務定義到可注入的服務類中,你可以讓它被任何組件使用。 通過在不同的環境中注入同一種服務的不同提供者,你還可以讓你的應用更具適應性。
當 Angular 創建組件類的新實例時,它會通過查看該組件類的構造函數,來決定該組件依賴哪些服務或其它依賴項。 比如 HeroListComponent 的構造函數中需要 HeroService:
constructor(private service: HeroService) { }當 Angular 發現某個組件依賴某個服務時,它會首先檢查是否該注入器中已經有了那個服務的任何現有實例。如果所請求的服務尚不存在,注入器就會使用以前注冊的服務提供者來制作一個,并把它加入注入器中,然后把該服務返回給 Angular。
是否創建新的依賴服務實例,取決于 provider 的具體類型。
當所有請求的服務已解析并返回時,Angular 可以用這些服務實例為參數,調用該組件的構造函數。
HeroService 的注入過程如下所示:從應用的 Injector 里獲取 HeroService 實例。
提供服務
對于要用到的任何服務,你必須至少注冊一個提供者。服務可以在自己的元數據中把自己注冊為提供者,這樣可以讓自己隨處可用。或者,你也可以為特定的模塊或組件注冊提供者。要注冊提供者,就要在服務的 @Injectable() 裝飾器中提供它的元數據,或者在 @NgModule() 或 @Component() 的元數據中。
默認情況下,Angular CLI 的 ng generate service 命令會在 @Injectable() 裝飾器中提供元數據來把它注冊到根注入器中。本教程就用這種方法注冊了 HeroService 的提供者:
@Injectable({providedIn: 'root', })什么是 Angular 依賴注入的 tree-shaking
When you provide the service at the root level, Angular creates a single, shared instance of HeroService and injects it into any class that asks for it. Registering the provider in the @Injectable() metadata also allows Angular to optimize an app by removing the service from the compiled app if it isn’t used, a process known as tree-shaking.
當你使用特定的 NgModule 注冊提供者時,該服務的同一個實例將會對該 NgModule 中的所有組件可用。要想在這一層注冊,請用 @NgModule() 裝飾器中的 providers 屬性:
@NgModule({providers: [BackendService,Logger],... })當你在組件級注冊提供者時,你會為該組件的每一個新實例提供該服務的一個新實例。 要在組件級注冊,就要在 @Component() 元數據的 providers 屬性中注冊服務提供者。
@Component({selector: 'app-hero-list',templateUrl: './hero-list.component.html',providers: [ HeroService ] })總結
以上是生活随笔為你收集整理的Angular 依赖注入的学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NullInjectorError:No
- 下一篇: Angular应用的router-out