摘要:上一篇說到了平臺(tái)實(shí)例在初始化的時(shí)候會(huì)創(chuàng)建根注入器那現(xiàn)在就一起看看注入器是如何創(chuàng)建的又是如何工作的所有引用的代碼都被簡(jiǎn)化了創(chuàng)建注入器程序初始化時(shí)調(diào)用的創(chuàng)建根注入器的靜態(tài)方法調(diào)用此方法會(huì)返回一個(gè)類型的實(shí)例也就是注入器類注入器的構(gòu)造函數(shù)在初始化過
上一篇說到了平臺(tái)實(shí)例在初始化的時(shí)候會(huì)創(chuàng)建根注入器,那現(xiàn)在就一起看看注入器是如何創(chuàng)建的,又是如何工作的.(所有引用的代碼都被簡(jiǎn)化了)
創(chuàng)建注入器程序初始化時(shí)調(diào)用的創(chuàng)建根注入器的靜態(tài)方法:
abstract class Injector{ static create(options: StaticProvider[]|{providers: StaticProvider[], parent?: Injector, name?: string},parent?: Injector): Injector { if (Array.isArray(options)) { return new StaticInjector(options, parent); } else { return new StaticInjector(options.providers, options.parent, options.name || null); } }
調(diào)用此方法會(huì)返回一個(gè)StaticInjector類型的實(shí)例(也就是注入器).
StaticInjector類
export class StaticInjector implements Injector { readonly parent: Injector; readonly source: string|null; private _records: Map; constructor(providers: StaticProvider[], parent: Injector = NULL_INJECTOR, source: string|null = null) { this.parent = parent; this.source = source; const records = this._records = new Map (); records.set(Injector, {token: Injector, fn: IDENT, deps: EMPTY, value: this, useNew: false}); records.set(INJECTOR, {token: INJECTOR, fn: IDENT, deps: EMPTY, value: this, useNew: false}); recursivelyProcessProviders(records, providers); } }
注入器的構(gòu)造函數(shù)在初始化過程中的操作:
設(shè)置當(dāng)前注入器的父注入器
設(shè)置注入器的源
新建注冊(cè)表(_records屬性,是一個(gè)Map類型)
將參數(shù)providers全部添加到注冊(cè)表中
向注冊(cè)表中添加服務(wù)調(diào)用了recursivelyProcessProviders函數(shù)
const EMPTY =[]; const MULTI_PROVIDER_FN = function (): any[] { return Array.prototype.slice.call(arguments) }; function recursivelyProcessProviders(records: Map , provider: StaticProvider) { if (provider instanceof Array) { for (let i = 0; i < provider.length; i++) { recursivelyProcessProviders(records, provider[i]); } } else (provider && typeof provider === "object" && provider.provide) { let token = resolveForwardRef(provider.provide);// 方法`resolveForwardRef`的作用可能是向前兼容,可以忽略 const resolvedProvider = resolveProvider(provider); if (provider.multi === true) { let multiProvider: Record | undefined = records.get(token); if (multiProvider) { if (multiProvider.fn !== MULTI_PROVIDER_FN) { throw multiProviderMixError(token); } } else { records.set(token, multiProvider = { token: provider.provide, deps: [], useNew: false, // 這個(gè)值在后面獲取依賴實(shí)例的時(shí)候會(huì)用到,當(dāng)做判斷條件 fn: MULTI_PROVIDER_FN, value: EMPTY // 這個(gè)值在后面獲取依賴實(shí)例的時(shí)候會(huì)用到,當(dāng)做判斷條件 }); } token = provider; multiProvider.deps.push({ token, options: OptionFlags.Default }); } records.set(token, resolvedProvider); } }
recursivelyProcessProviders函數(shù)具體的執(zhí)行過程:
如果provider是個(gè)數(shù)組,那就遍歷后依次調(diào)用此方法.
如果provider是個(gè)對(duì)象:
1 獲取token
let token = resolveForwardRef(provider.provide);
2 調(diào)用resolveProvider方法處理服務(wù)中可能出現(xiàn)的屬性和依賴,返回一個(gè)Record對(duì)象,此對(duì)象會(huì)作為token的值
function resolveProvider(provider: SupportedProvider): Record { const deps = computeDeps(provider); let fn: Function = function (value) { return value }; let value: any = []; // useUew用來標(biāo)識(shí)是否需要 new let useNew: boolean = false; let provide = resolveForwardRef(provider.provide); if (USE_VALUE in provider) { value = provider.useValue; } else if (provider.useFactory) { fn = provider.useFactory; } else if (provider.useExisting) { //do nothing } else if (provider.useClass) { useNew = true; fn = resolveForwardRef(provider.useClass); } else if (typeof provide == "function") { useNew = true; fn = provide; } else { throw staticError("StaticProvider does not have [useValue|useFactory|useExisting|useClass] or [provide] is not newable", provider); } return { deps, fn, useNew, value }; // provider中不同的屬性會(huì)返回包含不同值的對(duì)象 }
這個(gè)方法會(huì)先調(diào)用computeDeps函數(shù)處理服務(wù)需要的依賴,它將useExisting類型的服務(wù)也轉(zhuǎn)換成deps,最后返回[{ token, OptionFlags }]形式的數(shù)組(OptionFlags是枚舉常量)
function computeDeps(provider: StaticProvider): DependencyRecord[] { let deps: DependencyRecord[] = EMPTY; const providerDeps: any[] = provider.deps; if (providerDeps && providerDeps.length) { deps = []; for (let i = 0; i < providerDeps.length; i++) { let options = OptionFlags.Default; let token = resolveForwardRef(providerDeps[i]); deps.push({ token, options }); } } else if ((provider as ExistingProvider).useExisting) { const token = resolveForwardRef((provider as ExistingProvider).useExisting); deps = [{ token, options: OptionFlags.Default }]; } return deps; }
resolveProvider函數(shù)最終返回的Record對(duì)象有一個(gè)缺省值:
{ deps:[], // 包含依賴時(shí) [{ token, options },{ token, options }] fn:function(value) { return value }, useNew:false, value:[] }
執(zhí)行過程中會(huì)根據(jù)provider不同的屬性修改Record對(duì)象的變量為不同的值:
useValue : 修改value為useValue的值
useFactory : 修改fn為對(duì)應(yīng)的函數(shù)
useClass 或 typeof provide == "function"(令牌為一個(gè)函數(shù)時(shí)) : 修改fn為對(duì)應(yīng)的函數(shù),并設(shè)置useNew為true
useExisting : 不做修改,直接使用默認(rèn)值
3 如果是多處理服務(wù)(multi:ture)且為首次注冊(cè),那么在注冊(cè)表中額外注冊(cè)一個(gè)占位的Record
records.set(token, multiProvider ={ token: provider.provide, deps: [], useNew: false, fn: MULTI_PROVIDER_FN, value: EMPTY });
4 非多處理服務(wù)以token為鍵,多處理服務(wù)以provider對(duì)象為鍵,返回的Record對(duì)象為值,存入注冊(cè)表records中
從注入器中獲取實(shí)例服務(wù)注冊(cè)完,下一步就是怎么從注入器中獲取服務(wù)的實(shí)例了,這會(huì)調(diào)用StaticInjector的get方法
export class StaticInjector implements Injector { get(token: any, notFoundValue?: any, flags: InjectFlags = InjectFlags.Default): any { // 獲取token對(duì)應(yīng)的record const record = this._records.get(token); return resolveToken(token, record, this._records, this.parent, notFoundValue, flags); }
get方法調(diào)用了resolveToken函數(shù),這個(gè)函數(shù)會(huì)返回token對(duì)應(yīng)的實(shí)例(就是被注入的對(duì)象)
const EMPTY =[]; const CIRCULAR = IDENT; const IDENT = function (value: T): T { return value }; function resolveToken(token: any, record: Record | undefined, records: Map , parent: Injector, notFoundValue: any, flags: InjectFlags): any { let value; if (record && !(flags & InjectFlags.SkipSelf)) { value = record.value; if (value == CIRCULAR) { throw Error(NO_NEW_LINE + "Circular dependency"); } else if (value === EMPTY) { record.value = CIRCULAR; let obj = undefined; let useNew = record.useNew; let fn = record.fn; let depRecords = record.deps; let deps = EMPTY; if (depRecords.length) { deps = []; for (let i = 0; i < depRecords.length; i++) { const depRecord: DependencyRecord = depRecords[i]; const options = depRecord.options; const childRecord = options & OptionFlags.CheckSelf ? records.get(depRecord.token) : undefined; deps.push(tryResolveToken( depRecord.token, childRecord, records, !childRecord && !(options & OptionFlags.CheckParent) ? NULL_INJECTOR : parent, options & OptionFlags.Optional ? null : Injector.THROW_IF_NOT_FOUND, InjectFlags.Default)); } } record.value = value = useNew ? new (fn as any)(...deps) : fn.apply(obj, deps); } } else if (!(flags & InjectFlags.Self)) { value = parent.get(token, notFoundValue, InjectFlags.Default); } return value; }
函數(shù)中會(huì)先判斷當(dāng)前請(qǐng)求的token是否存在,如果不存在則去當(dāng)前注入器的父注入器中尋找,如果存在:
獲取token對(duì)應(yīng)的record
判斷record.value是否為[](非useValue類型的服務(wù)/多處理服務(wù)的默認(rèn)值是[]):
ture : 非useValue類型的服務(wù)/多處理服務(wù)或此服務(wù)沒有被創(chuàng)建過
查看是否包含依賴,包含則優(yōu)先創(chuàng)建依賴的實(shí)例,也是調(diào)用這個(gè)函數(shù)
根據(jù)record.fn創(chuàng)建當(dāng)前token對(duì)應(yīng)的實(shí)例并更新record.value(這里需要根據(jù)record.useNew來判斷是否需要用new來實(shí)例化,比如useFactory類型就不需要new,而useExisting更是直接返回了deps)
返回這個(gè)值
false : useValue類型的服務(wù)或此服務(wù)已經(jīng)被創(chuàng)建過
直接返回這個(gè)值
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/100059.html
摘要:以下簡(jiǎn)單介紹的重大變化。狀態(tài)轉(zhuǎn)交及對(duì)的支持這樣更便于在服務(wù)端和客戶之間共享應(yīng)用狀態(tài)。狀態(tài)轉(zhuǎn)交的相關(guān)文檔幾周后會(huì)發(fā)布。我們刪除很多以前廢棄的如,也公布了一些新的廢棄項(xiàng)。以上指南會(huì)詳細(xì)介紹這些變更。已知問題當(dāng)前已知與相關(guān)的問題。 我們很高興地宣布Angular 5.0.0——五角形甜甜圈發(fā)布啦!這又是一個(gè)主版本,包含新功能并修復(fù)了很多bug。它再次體現(xiàn)了我們把Angular做得更小、更快、...
摘要:以下簡(jiǎn)單介紹的重大變化。狀態(tài)轉(zhuǎn)交及對(duì)的支持這樣更便于在服務(wù)端和客戶之間共享應(yīng)用狀態(tài)。狀態(tài)轉(zhuǎn)交的相關(guān)文檔幾周后會(huì)發(fā)布。我們刪除很多以前廢棄的如,也公布了一些新的廢棄項(xiàng)。以上指南會(huì)詳細(xì)介紹這些變更。已知問題當(dāng)前已知與相關(guān)的問題。 我們很高興地宣布Angular 5.0.0——五角形甜甜圈發(fā)布啦!這又是一個(gè)主版本,包含新功能并修復(fù)了很多bug。它再次體現(xiàn)了我們把Angular做得更小、更快、...
摘要:模塊主要解決程序路由狀態(tài)改變和懶加載模塊問題。本文主要解釋程序啟動(dòng)后,是如何注冊(cè)開發(fā)者定義的路由集合的,和實(shí)例化對(duì)象的。第六個(gè)重要的對(duì)象就是,提供了初始導(dǎo)航功能。 @angular/router 模塊主要解決程序路由狀態(tài)改變和懶加載模塊問題。 比如,程序從路由狀態(tài) state1: /advisors/1/households/1 轉(zhuǎn)變?yōu)槁酚蔂顟B(tài) state2: /advisors/1/...
摘要:這些依賴對(duì)象也進(jìn)一步暴露了其設(shè)計(jì)思想。關(guān)鍵功能包括在上下文內(nèi)掛載在上下文外掛載在上下文外共享數(shù)據(jù)。在構(gòu)造必須依賴,所以可以直接創(chuàng)建嵌入視圖,然后手動(dòng)強(qiáng)制執(zhí)行變更檢測(cè)。提供了兩個(gè)指令和。 @angular/material 是 Angular 官方根據(jù) Material Design 設(shè)計(jì)語言提供的 UI 庫,開發(fā)人員在開發(fā) UI 庫時(shí)發(fā)現(xiàn)很多 UI 組件有著共同的邏輯,所以他們把這些共...
閱讀 1428·2021-10-11 11:12
閱讀 3258·2021-09-30 09:46
閱讀 1644·2021-07-28 00:14
閱讀 3147·2019-08-30 13:49
閱讀 2594·2019-08-29 11:27
閱讀 3248·2019-08-26 11:52
閱讀 610·2019-08-23 18:14
閱讀 3447·2019-08-23 16:27