您好,登錄后才能下訂單哦!
依賴注入(DI) 是 Angular 2 的核心,在深入了解DI的工作原理之前,我們必須先搞清楚 Provider 的概念。
在 Angular 2 中我們使用 Provider 來描述與 Token 關聯的依賴對象的創建方式。Angular 2 中依賴對象的創建方式有四種,它們分別是:
useClass
useValue
useFactory
useClass
@Injectable() export class ApiService { constructor( public http: Http, public loadingCtrl: LoadingController) { } ... } @NgModule({ ... providers: [ // 可使用簡潔的語法,即直接使用ApiService { provide: ApiService, useClass: ApiService } ]}) export class CoreModule { }
useValue
{ provide: 'API_URL', useValue: 'http://my.api.com/v1' }
useExisting
{ provide: 'ApiServiceAlias', useExisting: ApiService }
useFactory
export function configFactory(config: AppConfig) { return () => config.load(); } @NgModule({ ... providers: [ { provide: APP_INITIALIZER, useFactory: configFactory, deps: [AppConfig], multi: true } ]}) export class CoreModule { }
使用 Provider 的正確姿勢
1.創建 Token
Token 的作用是用來標識依賴對象,Token值可能是 Type、InjectionToken、OpaqueToken 類的實例或字符串。通常不推薦使用字符串,因為如果使用字符串存在命名沖突的可能性比較高。在 Angular 4.x 以前的版本我們一般使用 OpaqueToken 來創建 Token,而在 Angular 4.x 以上的版本版本,推薦使用 InjectionToken 來創建 Token 。詳細的內容可以參考, 如何解決 Angular 2 中 Provider 命名沖突。
2.根據實際需求選擇依賴對象的創建方式,如 useClass 、useValue、useExisting、useFactory
3.在 NgModule 或 Component 中注冊 providers
4.使用構造注入的方式,注入與 Token 關聯的依賴對象
/*** 封裝Http服務,如在每個Http的請求頭中添加token,類似于Ng1.x中的攔截器*/ @Injectable() export class ApiService { constructor( // 注入Angular 2 中的Http服務,與Ng1.x的區別: // 在Ng1.x中調用Http服務后,返回Promise對象 // 在Ng2.x中調用Http服務后,返回Observable對象 public http: Http) { } ...} /*** AppModule*/ @NgModule({ // 可使用簡潔的語法,即直接使用ApiService ... providers: [{ provide: ApiService, useClass: ApiService } ]}) export class AppModule { } /*** 系統首頁*/ @Component({ selector: 'page-home', templateUrl: 'home.html' }) export class HomePage { constructor( // 使用構造注入的方式,注入ApiService的實例對象 public apiService: ApiService) { } ngOnInit(): void { // 獲取首頁相關的數據 this.apiService.get(HOME_URL) .map(res => res.json()) // 返回的res對象是Response類型的實例 .subscribe(result => { ... }) } }
我有話說
1.當DI解析 Providers 時,都會對提供的每個 provider 進行規范化處理,即轉換成標準的形式。
function _normalizeProviders(providers: Provider[], res: Provider[]): Provider[] { providers.forEach(b => { if (b instanceof Type) { // 支持簡潔的語法,轉換為標準格式 res.push({provide: b, useClass: b}); } else if (b && typeof b == 'object' && (b as any).provide !== undefined) { res.push(b as NormalizedProvider); } else if (b instanceof Array) { _normalizeProviders(b, res); // 如果是數組,進行遞歸處理 } else { throw invalidProviderError(b); } }); return res; }
2.創建 Token 時為了避免命名沖突,盡量避免使用字符串作為Token。
3.若要創建模塊內通用的依賴對象,需要在 NgModule 中注冊相關的 provider,若在每個組件中,都有唯一的依賴對象,就需要在 Component 中注冊相關的 provider。
4.multi providers 的具體作用,具體請參考 - Angular2 Multi Providers
5.Provider 是用來描述與 Token 關聯的依賴對象的創建方式。當我們使用 Token 向 DI 系統獲取與之相關連的依賴對象時,DI 會根據已設置的創建方式,自動的創建依賴對象并返回給使用者。
Provider接口
export interface ClassProvider { // 用于設置與依賴對象關聯的Token值,Token值可能是Type、InjectionToken、OpaqueToken // 的實例或字符串 provide: any; useClass: Type<any>; // 用于標識是否multiple providers,若是multiple類型,則返回與Token關聯的依賴對象列表 multi?: boolean; } export interface ValueProvider { provide: any; useValue: any; multi?: boolean; } export interface ExistingProvider { provide: any; useExisting: any; multi?: boolean; } export interface FactoryProvider { provide: any; useFactory: Function; deps?: any[]; // 用于設置工廠函數的依賴對象 multi?: boolean; }
總結
在文章的最后,想舉一個現實生活中的例子,幫助初學者更好地理解 Angular 2 DI 和 Provider。
Provider
中的 token
可以理解為菜名,useClass、useValue可以理解為菜的烹飪方式,而依賴對象就是我們所點的菜,而 DI 系統就是我們的廚師了。如果沒有廚師,我們就得關心煮這道菜需要哪些原材料,怎么煮菜,重要的是還得自己煮,可想而知多麻煩。而有了廚師(DI),我們只要在菜譜上點菜,必要時備注一下烹飪方式,不過多久香噴噴的菜就上桌鳥~~~。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。