by Dor Moshe
通過Dor Moshe
Angular的后院:解決 組件依賴關系 (Angular’s Backyard: The Resolving of Components Dependencies)
This article originally appeared on dormoshe.io
這篇文章 最初出現在dormoshe.io
Many of us use the Hierarchical Dependency Injection mechanism of Angular. We use it through a service or a component to resolve another service or provider. But, do we know what Angular does in order to resolve the dependencies? Probably not, because Angular takes care of what we need to use it as a black box.
我們中的許多人都使用Angular的分層依賴注入機制。 我們通過服務或組件使用它來解析另一個服務或提供者。 但是,我們知道Angular為了解決依賴關系做什么嗎? 可能不是,因為Angular會照顧我們需要將其用作黑匣子的情況。
In this article, we’ll open the black box and explore the code of the component dependencies resolution mechanism.
在本文中,我們將打開黑盒,并探索組件依賴關系解析機制的代碼。
回到基礎 (Back to the basics)
Dependency Injection (DI) is a powerful pattern for managing code dependencies. Angular’s DI system creates and delivers dependent services “just-in-time”. Angular has its own DI framework, and we can’t build an Angular application without it.
依賴注入 (DI)是一種用于管理代碼依賴關系的強大模式。 Angular的DI系統可以 “及時” 創建并提供相關服務 。 Angular有自己的DI框架,沒有它我們就無法構建Angular應用程序。
The Angular DI system is actually a Hierarchical system. This system supports nested injectors in parallel with the component tree. An injector creates dependencies using providers. We can reconfigure the injectors at any level of that component tree. Behind the scenes, each component sets up its own injector with zero, one, or more providers defined for that component itself.
Angular DI系統實際上是一個層次結構 系統。 該系統支持與組件樹并行的嵌套進樣器。 注入程序使用提供程序創建依賴關系。 我們可以在該組件樹的任何級別重新配置注入器。 在幕后,每個組件都使用為該組件本身定義的零個,一個或多個提供程序來設置自己的注入器 。
解決順序 (Resolution Order)
The hierarchical DI has an order to the resolution of the dependencies. When a component requests a dependency, if it exists in the @Component.providers
array (the component injector), then this dependency will be supplied.
層次化DI對依存關系的解析具有順序。 當組件請求依賴項時,如果它存在于@Component.providers
數組(組件注入器)中,則將提供此依賴項。
Elsewhere, Angular continues to the parent component injector and checks again and again. If Angular doesn’t find an ancestor, it will supply this dependency via the application main injector. This is the core concept of the hierarchical DI mechanism.
在其他地方,Angular繼續使用父組件注入器并一次又一次地檢查。 如果Angular找不到祖先,它將通過應用程序主注入器提供此依賴關系。 這是分層DI機制的核心概念。
讓我們看一下代碼 (Let’s see the code)
When Angular instantiates a component, it calls the resolveDep
function. This function's signature contains the component view container, the element, the dependency definition and some more arguments. We will focus on the component view and the dependency object. The dependency object contains only one dependency of the component.
Angular實例化組件時,它將調用resolveDep
函數。 該函數的簽名包含組件視圖容器,元素,依賴項定義和更多參數。 我們將專注于組件視圖和依賴對象。 依賴性對象僅包含組件的一種依賴性。
Here is the resolveDep
function skeleton from the Angular GitHub repository:
這是Angular GitHub存儲庫中的resolveDep
函數框架:
The function skeleton contains the main concepts of the resolution, without the edge cases. The full code can be found here. In the next parts, we will explore the function skeleton.
函數框架包含分辨率的主要概念,不包含邊緣情況。 完整的代碼可以在這里找到。 在接下來的部分中,我們將探索功能框架。
保沙 (Pausa)
The Exclamation mark is a new feature of Typescript 2.0. The !
post-fix expression operator may be used to assert that its operand is non-null and non-undefined in contexts where the type checker is unable to conclude that fact. Angular uses this feature frequently, so we should not be afraid.
感嘆號是Typescript 2.0的新功能。 !
在類型檢查器無法得出結論的上下文中,可以使用后綴表達式運算符來斷言其操作數是非null且未定義的。 Angular經常使用此功能,因此我們不用擔心。
第1部分-準備 (Part 1 — Preparation)
The const startView = view;
code saves the original view (the view container of the component) in a variable because the view variable will change soon.
const startView = view;
代碼將原始視圖(組件的視圖容器)保存在一個變量中,因為view變量將很快更改。
The const tokenKey = depDef.tokenKey;
code fetches the tokenKey or the dependency key, for example, HeroService_4. This key builds by the dependency name and a generated number to handle the dependency uniquely.
const tokenKey = depDef.tokenKey;
代碼獲取tokenKey或依賴項鍵,例如HeroService_4 。 該鍵由依賴項名稱和生成的數字構建,以唯一地處理依賴項。
第2部分-源組件和祖先搜索 (Part 2 —Source component and Ancestors search)
The while loop implements the stages of checking the source @Component.providers
and the ancestor components. According to the dependency token key, the source component providers will be checked in lines 1–3:
while循環實現檢查源@Component.providers
和祖先組件的階段。 根據依賴性令牌密鑰,將在第1–3行中檢查源組件提供者:
If the provider exists on line 4, then the source component satisfies the dependency. So, if the dependency was instantiated in the past on line 6, the instance will return by the resolveDep
function at line 10. If this is the first time that the component or its children ask for the dependency it will be created at line 7 and will return by the resolveDep
function at line 10.
如果提供程序存在于第4行,則源組件滿足依賴性。 因此,如果依賴關系是在過去的第6行實例化的,則實例將在第10行由resolveDep
函數返回。如果這是組件或其子級第一次請求依賴關系,它將在第7行創建,然后將由第10行的resolveDep
函數返回。
If the dependency is not found in the view
component injector, the elDef = viewParentEl(view) !;
and view = view.parent !;
will be called to advance the variable to the parent element. The while
loop will continue running until the dependency is found in the ancestor injector. If the dependency is still not found after checking all ancestors, the while
loop will end and the third part will come into action.
如果在view
組件注入器中未找到依賴項,則elDef = viewParentEl(view) !;
和view = view.parent !;
將被調用以將變量前進到父元素。 while
循環將繼續運行,直到在祖先注入器中找到相關性為止。 如果在檢查所有祖先后仍未找到依賴項,則while
循環將結束,并且第三部分將開始起作用。
第3部分-根注射器 (Part 3 — Root injector)
If come to this part, the dependency can’t be satisfied by any of the component ancestors injectors. Then the startView
or the source component will be checked at line 1:
如果涉及到這一部分,則任何組件祖先注入器都無法滿足這種依賴性。 然后將在第1行檢查startView
或源組件:
If the source component or one of its ancestor components was loaded by the Router Outlet (the router component), the root injector is the Outlet Injector. This injector supplies some dependencies like the Router service. Otherwise, the root injector is the bootstrap component’s injector.
如果源組件或其祖先組件之一是由路由器出口(路由器組件)加載的,則根注入器為出口注入器 。 該注入器提供了一些依賴性,例如路由器服務。 否則,根注入器是自舉組件的注入器。
If the dependency is found at line 3, then the value will be returned by the resolveDep
function. In the other case, part 4 will come into action.
如果在第3行找到依賴項,那么resolveDep
函數將返回該值。 在其他情況下,第4部分將生效。
第4部分-應用模塊注入器 (Part 4 — Application module injector)
When we come to this part, it means that the dependency can’t be satisfied by part 2 and part 3. This is the last chance to satisfy the dependency. This part’s code tries to get the dependency from the application module injector or the root module. This module contains the application-wide dependencies:return startView.root.ngModule.injector.get(depDef.token,notFoundValue);
當涉及到這一部分時,這意味著第2部分和第3部分不能滿足依賴關系。這是滿足依賴關系的最后機會。 這部分的代碼試圖從應用程序模塊注入器或根模塊獲取依賴關系。 此模塊包含應用程序范圍的依賴項: return startView.root.ngModule.injector.get(depDef.token,notFoundValue);
This part finishes the resolveDep
flow. If the dependency is not found, then Angular can’t satisfy this dependency and it should throw an exception.
本部分完成resolveDep
流程。 如果找不到依賴關系,則Angular無法滿足此依賴關系,因此應引發異常。
結論 (Conclusion)
The Hierarchical DI is a core feature that Angular leans on a lot. Sometimes, the resolution process looks complicated and long. It’s very convenient to leave Angular to manage this flow and enjoy the ease of use. Now, after we hiked in the backyard of the component dependency resolution, we know what to expect when we use it.
分層DI是Angular所依賴的一項核心功能。 有時,解析過程看起來很復雜且漫長。 離開Angular管理此流程并享受易用性非常方便。 現在,當我們在組件依賴關系解決方案的后院爬升之后,我們知道使用它時會發生什么。
You can follow me on dormoshe.io or Twitter to read more about Angular, JavaScript and web development.
您可以在dormoshe.io或Twitter上關注我,以了解有關Angular,JavaScript和Web開發的更多信息。
翻譯自: https://www.freecodecamp.org/news/angulars-backyard-the-resolving-of-component-dependencies-2015b40e5bd1/