您好,登錄后才能下訂單哦!
這篇文章主要介紹“Angular依賴注入體系中的基本概念是什么”,在日常操作中,相信很多人在Angular依賴注入體系中的基本概念是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Angular依賴注入體系中的基本概念是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
既然要介紹 Angular 框架的依賴注入設計,那么先鋪墊一下依賴注入的基本概念。我們常常會搞混依賴倒置原則(DIP)、控制反轉(IoC)、依賴注入(DI)這幾個概念,因此這里會先簡單介紹一下。
低耦合、高內聚大概是每個系統的設計目標之一,而為此產生了很多的設計模式和理念,其中便包括依賴倒置原則、控制反轉的設計思想。
(1) 依賴倒置原則(DIP)。
依賴倒置原則的原始定義為:
高層模塊不應該依賴低層模塊,兩者都應該依賴其抽象;
抽象不應該依賴細節,細節應該依賴抽象。
簡單說便是:模塊間不應該直接依賴對方,應該依賴一個抽象的規則(接口或者時抽象類)。
(2) 控制反轉(IoC)。
控制反轉的定義為:模塊間的依賴關系從程序內部提到外部來實例化管理。即對象在被創建的時候,由一個調控系統內所有對象的外界實體控制,并將其所依賴的對象的引用傳遞(注入)給它。
實現控制反轉主要有兩種方式:
依賴注入:被動的接收依賴對象
依賴查找:主動索取依賴的對象
(3) 依賴注入。
依賴注入,是控制反轉的最為常見的一種技術。
依賴倒置和控制反轉兩者相輔相成,常常可以一起使用,可有效地降低模塊間的耦合。
在 Angular 中,同樣使用了依賴注入的技術,DI 框架會在實例化某個類時,向其提供這個類所聲明的依賴項(依賴項:指當類需要執行其功能時,所需要的服務或對象)。
Angular 中的依賴注入基本上是圍繞著組件或者是模塊展開的,主要用于給新建的組件提供依賴。
Angular 中主要的依賴注入機制是注入器機制:
應用中所需的任何依賴,都必須使用該應用的注入器來注冊一個提供者,以便注入器可以使用這個提供者來創建新實例
Angular 會在啟動過程中,創建全應用級注入器以及所需的其它注入器
這里面主要涉及兩個概念,分別是Injector 注入器和Provider 提供商,我們來看看。
Injector 注入器用于創建依賴,會維護一個容器來管理這些依賴,并盡可能地復用它們。注入器會提供依賴的一個單例,并把這個單例對象注入到多個組件中。
顯然,作為一個用來創建、管理、維護依賴的容器,注入器的功能很簡單:創建依賴實例、獲取依賴實例、管理依賴實例。我們也可以從抽象類Injector
的源碼中看出來:
export abstract class Injector { // 找不到依賴 static THROW_IF_NOT_FOUND = THROW_IF_NOT_FOUND; // NullInjector 是樹的頂部 // 如果你在樹中向上走了很遠,以至于要在 NullInjector 中尋找服務,那么將收到錯誤消息,或者對于 @Optional(),返回 null static NULL: Injector = new NullInjector(); // 根據提供的 Token 從 Injector 檢索實例 abstract get<T>( token: Type<T> | AbstractType<T> | InjectionToken<T>, notFoundValue?: T, flags?: InjectFlags ): T; // 創建一個新的 Injector 實例,該實例提供一個或多個依賴項 static create(options: { providers: StaticProvider[]; parent?: Injector; name?: string; }): Injector; // ??defineInjectable 用于構造一個 InjectableDef // 它定義 DI 系統將如何構造 Token,并且在哪些 Injector 中可用 static ?prov = ??defineInjectable({ token: Injector, providedIn: "any" as any, // ??inject 生成的指令:從當前活動的 Injector 注入 Token factory: () => ??inject(INJECTOR), }); static __NG_ELEMENT_ID__ = InjectorMarkers.Injector; }
也就是說,我們可以將需要共享的依賴實例添加到注入器中,并通過 Token 查詢和檢索注入器來獲取相應的依賴實例。
需要注意的是,Angular 中的注入器是分層的,因此查找依賴的過程也是向上遍歷注入器樹的過程。
這是因為在 Angular 中,應用是以模塊的方式組織的,具體可以參考5.模塊化組織篇。一般來說,頁面的 DOM 是以html
作為根節點的樹狀結構,以此為基礎,Angular 應用中的組件和模塊也是與之相伴的樹狀結構。
而注入器服務于組件和模塊,同樣是掛載與模塊和組織上的樹狀結構。因此,Injector 也劃分為模塊和組件級別,可分別為組件和模塊提供依賴的具體實例。注入器是可繼承的,這意味著如果指定的注入器無法解析某個依賴,它就會請求父注入器來解析它,我們同樣可以從上面的創建注入器代碼中看到:
// 創建一個新的 Injector 實例,可傳入 parent 父注入器 static create(options: {providers: StaticProvider[], parent?: Injector, name?: string}): Injector;
在某個注入器的范圍內,服務是單例的。也就是說,在指定的注入器中最多只有某個服務的最多一個實例。如果不希望在所有地方都使用該服務的同一個實例,則可以通過注冊多個注入器、并按照需要關聯到組件和模塊中的方式,來按需共享某個服務依賴的實例。
我們可以看到創建一個新的Injector
實例時,傳入的參數包括Provider
,這是因為Injector
不會直接創建依賴,而是通過Provider
來完成的。每個注入器會維護一個提供者的列表,并根據組件或其它服務的需要,用它們來提供服務的實例。
Provider 提供者用來告訴注入器應該如何獲取或創建依賴,要想讓注入器能夠創建服務(或提供其它類型的依賴),必須使用某個提供者配置好注入器。
一個提供者對象定義了如何獲取與 DI 令牌(token) 相關聯的可注入依賴,而注入器會使用這個提供者來創建它所依賴的那些類的實例。
關于 DI 令牌:
當使用提供者配置注入器時,就會把提供者和一個 DI 令牌關聯起來;
注入器維護一個內部令牌-提供者的映射表,當請求一個依賴項時就會引用它,令牌就是這個映射表的鍵。
提供者的類型很多,從官方文檔中可以閱讀它們的具體定義:
export type Provider = | TypeProvider | ValueProvider | ClassProvider | ConstructorProvider | ExistingProvider | FactoryProvider | any[];
提供者的解析過程如下:
function resolveReflectiveFactory( provider: NormalizedProvider ): ResolvedReflectiveFactory { let factoryFn: Function; let resolvedDeps: ReflectiveDependency[]; if (provider.useClass) { // 使用類來提供依賴 const useClass = resolveForwardRef(provider.useClass); factoryFn = reflector.factory(useClass); resolvedDeps = _dependenciesFor(useClass); } else if (provider.useExisting) { // 使用已有依賴 factoryFn = (aliasInstance: any) => aliasInstance; // 從根據 token 獲取具體的依賴 resolvedDeps = [ ReflectiveDependency.fromKey(ReflectiveKey.get(provider.useExisting)), ]; } else if (provider.useFactory) { // 使用工廠方法提供依賴 factoryFn = provider.useFactory; resolvedDeps = constructDependencies(provider.useFactory, provider.deps); } else { // 使用提供者具體的值作為依賴 factoryFn = () => provider.useValue; resolvedDeps = _EMPTY_LIST; } // return new ResolvedReflectiveFactory(factoryFn, resolvedDeps); }
根據不同類型的提供者,通過解析之后,得到由注入器 Injector 使用的提供者的內部解析表示形式:
export interface ResolvedReflectiveProvider { // 鍵,包括系統范圍內的唯一 id,以及一個 token key: ReflectiveKey; // 可以返回由鍵表示的對象的實例的工廠函數 resolvedFactories: ResolvedReflectiveFactory[]; // 指示提供者是多提供者,還是常規提供者 multiProvider: boolean; }
提供者可以是服務類ClassProvider
本身,如果把服務類指定為提供者令牌,那么注入器的默認行為是用new
來實例化那個類。
在 Angular 中,服務就是一個帶有@Injectable
裝飾器的類,它封裝了可以在應用程序中復用的非 UI 邏輯和代碼。Angular 把組件和服務分開,是為了增進模塊化程度和可復用性。
用@Injectable
標記一個類,以確保編譯器將在注入類時生成必要的元數據(元數據在 Angular 中也是很重要的一部分),以創建類的依賴項。
@Injectable
裝飾器的類會在編譯之后,得到 Angular 可注入對象:
// 根據其 Injectable 元數據,編譯 Angular 可注入對象,并對結果進行修補 export function compileInjectable(type: Type<any>, srcMeta?: Injectable): void { // 該編譯過程依賴 @angular/compiler // 可參考編譯器中的 compileFactoryFunction compileInjectable 實現 }
Angular 中可注入對象(InjectableDef
)定義 DI 系統將如何構造 token 令牌,以及在哪些注入器(如果有)中可用:
export interface ??InjectableDef<T> { // 指定給定類型屬于特定注入器,包括 root/platform/any/null 以及特定的 NgModule providedIn: InjectorType<any> | "root" | "platform" | "any" | null; // 此定義所屬的令牌 token: unknown; // 要執行以創建可注入實例的工廠方法 factory: (t?: Type<any>) => T; // 在沒有顯式注入器的情況下,存儲可注入實例的位置 value: T | undefined; }
使用@Injectable()
的providedIn
時,優化工具可以進行 Tree-shaking 優化,從而刪除應用程序中未使用的服務,以減小捆綁包尺寸。
到此,關于“Angular依賴注入體系中的基本概念是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。