
เนื่องจากเฟรมเวิร์กส่วนหน้าได้รับการออกแบบ "สำหรับโปรเจ็กต์ส่วนหน้าขนาดใหญ่" Angular จึงมีการออกแบบมากมายที่ควรค่าแก่การอ้างอิงและการเรียนรู้ ซีรีส์นี้ใช้เพื่อศึกษาหลักการใช้งานของการออกแบบและฟังก์ชันเหล่านี้เป็นหลัก บทความนี้มุ่งเน้นไปที่คุณลักษณะที่ใหญ่ที่สุดของ Angular - dependency insert และแนะนำการออกแบบ dependency injection หลายระดับใน Angular [บทช่วยสอนที่เกี่ยวข้องที่แนะนำ: "บทช่วยสอนเชิงมุม"]
ในบทความก่อนหน้านี้ เราได้แนะนำ Injectot injector ผู้ให้ Provider และกลไกของหัวฉีดใน Angular ดังนั้นในแอปพลิเคชันเชิงมุม ส่วนประกอบและโมดูลจะแบ่งปันการพึ่งพาได้อย่างไร?
กระบวนการพึ่งพาการฉีดของส่วนประกอบและโมดูลแยกกันไม่ออกจากการออกแบบการฉีดพึ่งพาหลายระดับของ Angular
ดังที่เราได้กล่าวไว้ก่อนหน้านี้ injector ใน Angular สามารถสืบทอดได้และเป็นลำดับชั้น
ใน Angular มีลำดับชั้นของ injector สองลำดับ:
ModuleInjector Module Injector: กำหนดค่า ModuleInjector ในลำดับชั้นนี้โดยใช้ @NgModule() หรือ @Injectable() คำอธิบายประกอบ ModuleInjectorElementInjector Injector: สร้างโมดูลโดยปริยายในทุกองค์ประกอบ DOM ทั้ง injectors และ element injectors นั้นมีโครงสร้างแบบต้นไม้ แต่ลำดับชั้นไม่เหมือนกันทุกประการ
โครงสร้างลำดับชั้นของโมดูลหัวฉีดไม่เพียงเกี่ยวข้องกับการออกแบบโมดูลในแอปพลิเคชันเท่านั้น แต่ยังมีโครงสร้างลำดับชั้นของหัวฉีดโมดูลแพลตฟอร์ม (PlatformModule) และโมดูลแอปพลิเคชัน (AppModule) หัวฉีด
ในคำศัพท์เฉพาะทางเชิงมุม แพลตฟอร์มคือบริบทที่แอปพลิเคชันเชิงมุมทำงาน แพลตฟอร์มที่พบบ่อยที่สุดสำหรับแอปพลิเคชันเชิงมุมคือเว็บเบราว์เซอร์ แต่อาจเป็นระบบปฏิบัติการของอุปกรณ์พกพาหรือเว็บเซิร์ฟเวอร์ก็ได้
เมื่อแอปพลิเคชัน Angular เริ่มต้นขึ้น มันจะสร้างเลเยอร์แพลตฟอร์ม:
แพลตฟอร์มนั้นเป็นจุดเริ่มต้นของ Angular บนหน้าเว็บ แต่ละหน้ามีเพียงแพลตฟอร์มเดียวที่ทำงานบนเพจ และบริการทั่วไปทั้งหมดจะเชื่อมโยงกับAngular
ซึ่งรวมถึงฟังก์ชันต่างๆ เป็นหลัก เช่น การสร้างอินสแตนซ์โมดูลและการทำลายล้าง:
@Injectable()
ส่งออกคลาส PlatformRef {
// ส่งผ่านหัวฉีดในฐานะตัวสร้างแพลตฟอร์มหัวฉีด (ส่วนตัว _หัวฉีด: หัวฉีด) {}
// สร้างอินสแตนซ์ของ @NgModule สำหรับแพลตฟอร์มที่กำหนดสำหรับการคอมไพล์ออฟไลน์ bootstrapModuleFactory<M>(moduleFactory: NgModuleFactory<M>, options?: BootstrapOptions):
สัญญา<NgModuleRef<M>> {}
// ใช้รันไทม์คอมไพเลอร์ที่กำหนด สร้างอินสแตนซ์ของ @NgModule สำหรับแพลตฟอร์มที่กำหนด bootstrapModule<M>(
ประเภทโมดูล: ประเภท <M>,
คอมไพเลอร์ตัวเลือก: (CompilerOptions&BootstrapOptions)|
Array<CompilerOptions&BootstrapOptions> = []): สัญญา<NgModuleRef<M>> {}
// ลงทะเบียนผู้ฟังที่จะถูกเรียกเมื่อทำลายแพลตฟอร์ม onDestroy(callback: () => void): void {}
// รับแพลตฟอร์มหัวฉีด // แพลตฟอร์มหัวฉีดเป็นหัวฉีดหลักสำหรับทุกแอปพลิเคชันเชิงมุมบนเพจและจัดเตรียมผู้ให้บริการซิงเกิลตัน รับหัวฉีด (): หัวฉีด {}
// ทำลายแพลตฟอร์ม Angular ปัจจุบันและแอปพลิเคชัน Angular ทั้งหมดบนเพจ รวมถึงการทำลายโมดูลและผู้ฟังทั้งหมดที่ลงทะเบียนบนแพลตฟอร์ม destroy() {}
} ที่จริงแล้ว เมื่อแพลตฟอร์มเริ่มต้น (ในวิธี bootstrapModuleFactory ) ngZoneInjector จะถูกสร้างขึ้นใน ngZone.run เพื่อให้บริการที่สร้างอินสแตนซ์ทั้งหมดถูกสร้างขึ้นในโซน Angular และ ApplicationRef (แอปพลิเคชันเชิงมุมที่ทำงานบนเพจ) จะอยู่ใน โซนเชิงมุมที่สร้างขึ้นภายนอก
เมื่อเปิดตัวในเบราว์เซอร์ แพลตฟอร์มเบราว์เซอร์จะถูกสร้างขึ้น:
ส่งออก const platformBrowser: (extraProviders?: StaticProvider[]) => PlatformRef =
createPlatformFactory (แพลตฟอร์มคอร์, 'เบราว์เซอร์', INTERNAL_BROWSER_PLATFORM_PROVIDERS);
// ในหมู่พวกเขา แพลตฟอร์ม platformCore จะต้องรวมอยู่ในแพลตฟอร์มอื่น ๆ ส่งออก const platformCore = createPlatformFactory(null, 'core', _CORE_PLATFORM_PROVIDERS) เมื่อสร้างแพลตฟอร์มโดยใช้โรงงานแพลตฟอร์ม (เช่น createPlatformFactory ด้านบน) แพลตฟอร์มของหน้า จะถูกเตรียมใช้งานโดยปริยาย:
ฟังก์ชันการส่งออก createPlatformFactory(
parentPlatformFactory: ((extraProviders?: StaticProvider[]) => PlatformRef)|null ชื่อ: สตริง
ผู้ให้บริการ: StaticProvider[] = []): (extraProviders?: StaticProvider[]) => PlatformRef {
const desc = `แพลตฟอร์ม: ${name}`;
const marker = new InjectionToken(desc); // DI โทเค็นส่งคืน (extraProviders: StaticProvider[] = []) => {
ให้แพลตฟอร์ม = getPlatform();
// หากแพลตฟอร์มถูกสร้างขึ้น จะไม่มีการประมวลผลหาก (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
ถ้า (parentPlatformFactory) {
// หากมีแพลตฟอร์มหลัก ให้ใช้แพลตฟอร์มหลักโดยตรงและอัปเดต parentPlatformFactory ผู้ให้บริการที่เกี่ยวข้อง (
provider.concat(extraProviders).concat({ระบุ: เครื่องหมาย, useValue: true}));
} อื่น {
const injectedProviders: StaticProvider[] =
ผู้ให้บริการ.concat(extraProviders).concat({ให้: เครื่องหมาย, useValue: จริง}, {
ให้: INJECTOR_SCOPE,
useValue: 'แพลตฟอร์ม'
-
// หากไม่มีแพลตฟอร์มหลัก ให้สร้างหัวฉีดใหม่และสร้างแพลตฟอร์ม createPlatform(Injector.create({providers: injectedProviders, name: desc}));
-
-
กลับ assertPlatform (เครื่องหมาย);
-
} จากกระบวนการข้างต้น เรารู้ว่าเมื่อแอปพลิเคชัน Angular สร้างแพลตฟอร์ม มันจะสร้างโมดูล injector ของแพลตฟอร์ม ModuleInjector นอกจากนี้เรายังสามารถเห็นจากคำจำกัดความ Injector ในส่วนก่อนหน้าว่า NullInjector อยู่ด้านบนสุดของหัวฉีดทั้งหมด:
ส่งออกคลาสนามธรรมหัวฉีด {
โมฆะคงที่: หัวฉีด = NullInjector ใหม่ ();
} ดังนั้น ด้านบนของแพลตฟอร์มโมดูลหัวฉีด จะมี NullInjector() ใต้หัวฉีดโมดูลแพลตฟอร์ม ยังมีหัวฉีดโมดูลแอปพลิเคชันด้วย
แต่ละแอปพลิเคชันมีโมดูล Angular อย่างน้อยหนึ่งโมดูล โมดูลรูทคือโมดูลที่ใช้ในการเริ่มแอปพลิเคชันนี้:
@NgModule({ provider: APPLICATION_MODULE_PROVIDERS })
ส่งออกคลาส ApplicationModule {
// ApplicationRef ต้องการบูตสแตรปเพื่อจัดเตรียมตัวสร้างส่วนประกอบ (appRef: ApplicationRef) {}
} โมดูลแอปพลิเคชันรูท AppModule ถูกส่งออกอีกครั้งโดย BrowserModule และเมื่อเราสร้างแอปพลิเคชันใหม่โดยใช้คำสั่ง new ของ CLI โมดูลนั้นจะถูกรวมไว้ในรูท AppModule โดยอัตโนมัติ ในโมดูลรูทของแอปพลิเคชัน ผู้ให้บริการจะเชื่อมโยงกับโทเค็น DI ในตัวที่ใช้ในการกำหนดค่ารูทอินเจกเตอร์สำหรับบูตสแตรป
Angular ยังเพิ่ม ComponentFactoryResolver ให้กับโมดูลรูทหัวฉีด parser นี้จัดเก็บกลุ่มโรงงานของ entryComponents ดังนั้นจึงมีหน้าที่ในการสร้างส่วนประกอบแบบไดนามิก
ณ จุดนี้ เราสามารถเรียงลำดับความสัมพันธ์แบบลำดับชั้นของโมดูลหัวฉีดได้:
ระดับบนสุดของแผนผังโมดูลหัวฉีดคือโมดูลรูทของแอปพลิเคชัน (AppModule) ที่เรียกว่ารูท
มีหัวฉีดสองตัวที่อยู่เหนือรูท ตัวหนึ่งคือโมดูลแพลตฟอร์ม (PlatformModule) และอีกตัวคือ NullInjector()
ดังนั้นลำดับชั้นของโมดูลหัวฉีดจึงเป็นดังนี้:

ในการใช้งานจริงของเรา น่าจะเป็นดังนี้:

Angular DI มีสถาปัตยกรรมการฉีดแบบเป็นชั้น ซึ่งหมายความว่าหัวฉีดระดับล่างสามารถสร้างอินสแตนซ์บริการของตัวเองได้
ดังที่ได้กล่าวไว้ก่อนหน้านี้ มีลำดับชั้นของ injector สองลำดับชั้นใน Angular ได้แก่ module injector และ element injector
เมื่อโมดูลโหลดแบบขี้เกียจเริ่มมีการใช้กันอย่างแพร่หลายใน Angular ปัญหาก็เกิดขึ้น: ระบบการฉีดพึ่งพาทำให้อินสแตนซ์ของโมดูลโหลดแบบขี้เกียจเพิ่มเป็นสองเท่า
ในการแก้ไขนี้ มีการนำการออกแบบใหม่มาใช้: หัวฉีดใช้ต้นไม้สองต้นขนานกัน ต้นหนึ่งสำหรับองค์ประกอบ และอีกต้นหนึ่งสำหรับโมดูล
Angular สร้างโรงงานโฮสต์สำหรับ entryComponents ทั้งหมด ซึ่งเป็นมุมมองรูทสำหรับส่วนประกอบอื่น ๆ ทั้งหมด
ซึ่งหมายความว่าทุกครั้งที่เราสร้างส่วนประกอบ Angular แบบไดนามิก มุมมองรูท ( RootData ) จะถูกสร้างขึ้นด้วยข้อมูลรูท ( RootView ):
คลาส ComponentFactory_ ขยาย ComponentFactory<any>{
สร้าง(
หัวฉีด: หัวฉีด, projectableNodes?: ใด ๆ []], rootSelectorOrNode?: string | ใด ๆ
ngModule?: NgModuleRef<ใด ๆ>): ComponentRef<ใด ๆ> {
ถ้า (!ngModule) {
โยนข้อผิดพลาดใหม่ ('ควรระบุ ngModule');
-
const viewDef = solveDefinition (this.viewDefFactory);
const componentNodeIndex = viewDef.nodes[0].element!.componentProvider!.nodeIndex;
//สร้างมุมมองรูทโดยใช้ข้อมูลรูท มุมมอง const = Services.createRootView(
หัวฉีด, projectableNodes ||. [], rootSelectorOrNode, viewDef, ngModule, EMPTY_CONTEXT);
// ตัวเข้าถึงสำหรับ view.nodes const component = asProviderData(view, componentNodeIndex).instance;
ถ้า (rootSelectorOrNode) {
view.renderer.setAttribute(asElementData(ดู, 0).renderElement, 'ng-version', VERSION.full);
-
//สร้างส่วนประกอบส่งคืน ComponentRef_ ใหม่ (ดู ViewRef_ ใหม่ (ดู) ส่วนประกอบ);
-
} ข้อมูลรูท ( RootData ) มีการอ้างอิงถึง elInjector และ ngModule injectors:
function createRootData(
elInjector: หัวฉีด, ngModule: NgModuleRef <ใด ๆ>, rendererFactory: RendererFactory2,
projectableNodes: ใด ๆ [] [], rootSelectorOrNode: ใด ๆ): RootData {
const เจลทำความสะอาด = ngModule.injector.get (เจลทำความสะอาด);
const errorHandler = ngModule.injector.get (ตัวจัดการข้อผิดพลาด);
const renderer = rendererFactory.createRenderer (โมฆะ, โมฆะ);
กลับ {
ngโมดูล,
หัวฉีด: elInjector,
โหนดที่สามารถฉายภาพได้,
selectorOrNode: rootSelectorOrNode,
น้ำยาฆ่าเชื้อ,
โรงงานเรนเดอร์,
เรนเดอร์,
ตัวจัดการข้อผิดพลาด,
-
} ขอแนะนำ element injector tree เนื่องจากการออกแบบนี้ค่อนข้างเรียบง่าย โดยการเปลี่ยนลำดับชั้นของหัวฉีด ให้หลีกเลี่ยงการสลับโมดูลและส่วนประกอบของหัวฉีด ส่งผลให้โมดูลที่โหลดแบบ Lazy โหลดเป็นสองเท่า เนื่องจากแต่ละหัวฉีดมีพาเรนต์เพียงตัวเดียว และแต่ละความละเอียดจะต้องค้นหาหัวฉีดเพียงตัวเดียวเพื่อดึงข้อมูลการขึ้นต่อกัน
ในเชิงมุม มุมมองเป็นตัวแทนของเทมเพลต ซึ่งมีโหนดประเภทต่างๆ ซึ่งได้แก่ โหนดองค์ประกอบ ซึ่งอยู่บนโหนดนี้:
อินเทอร์เฟซการส่งออก ElementDef {
-
// ผู้ให้บริการสาธารณะของ DI มองเห็นได้ในมุมมองนี้ publicProviders: {[tokenKey: string]: NodeDef}|null;
// เหมือนกับที่มองเห็นได้PublicProviders แต่ยังรวมถึงผู้ให้บริการส่วนตัวที่อยู่ในองค์ประกอบนี้ allProviders: {[tokenKey: string]: NodeDef}|null;
} ElementInjector จะว่างเปล่าตามค่าเริ่มต้น เว้นแต่จะกำหนดค่าในแอตทริบิวต์ของ providers ของ @Directive() หรือ @Component()
เมื่อ Angular สร้างองค์ประกอบ injector สำหรับองค์ประกอบ HTML ที่ซ้อนกัน มันจะสืบทอดมาจากองค์ประกอบหลัก injector หรือกำหนดองค์ประกอบหลัก injector ให้กับคำจำกัดความของโหนดลูกโดยตรง
หากองค์ประกอบ injector ในองค์ประกอบ HTML ลูกมีผู้ให้บริการ ก็ควรจะสืบทอดมา มิฉะนั้น ไม่จำเป็นต้องสร้างหัวฉีดแยกต่างหากสำหรับคอมโพเนนต์ลูก และสามารถแก้ไขการขึ้นต่อกันได้โดยตรงจากหัวฉีดของพาเรนต์ หากจำเป็น
แล้วองค์ประกอบหัวฉีดและโมดูลหัวฉีดเริ่มกลายเป็นต้นไม้คู่ขนานกันที่ไหน?
เรารู้อยู่แล้วว่าโมดูลรูทของแอปพลิเคชัน ( AppModule ) จะถูกรวมไว้ในรูท AppModule โดยอัตโนมัติเมื่อสร้างแอปพลิเคชันใหม่โดยใช้คำสั่ง new ของ CLI
เมื่อแอปพลิเคชัน ( ApplicationRef ) เริ่มต้น ( bootstrap ) entryComponent จะถูกสร้างขึ้น:
const compRef = componentFactory.create(Injector.NULL, [], selectorOrNode, ngModule);
กระบวนการนี้จะสร้างมุมมองรูท ( RootView ) โดยใช้ข้อมูลรูท ( RootData ) และองค์ประกอบรูท injector จะถูกสร้างขึ้น โดยที่ elInjector คือ Injector.NULL
ที่นี่ แผนผังหัวฉีดของ Angular แบ่งออกเป็นแผนผังหัวฉีดองค์ประกอบและแผนผังหัวฉีดโมดูล ซึ่งเป็นต้นไม้คู่ขนานทั้งสองนี้
Angular จะสร้างหัวฉีดย่อยเป็นประจำ เมื่อใดก็ตามที่ Angular สร้างอินสแตนซ์ส่วนประกอบ providers ที่ระบุใน @Component() มันจะสร้างหัวฉีดย่อยใหม่สำหรับอินสแตนซ์ด้วย ในทำนองเดียวกัน เมื่อมีการโหลด NgModule ใหม่ ณ รันไทม์ Angular จะสามารถสร้าง injector ให้ด้วยผู้ให้บริการของตัวเองได้
โมดูลย่อยและหัวฉีดส่วนประกอบมีความเป็นอิสระจากกัน และแต่ละโมดูลจะสร้างอินสแตนซ์ของตัวเองสำหรับบริการที่มีให้ เมื่อ Angular ทำลายอินสแตนซ์ NgModule หรือส่วนประกอบ ก็จะทำลายตัวฉีดเหล่านี้และอินสแตนซ์บริการเหล่านั้นในตัวฉีดด้วย
เชิงมุม ด้านบนเราได้แนะนำแผนผังหัวฉีดสองประเภทใน Angular: แผนผังโมดูลหัวฉีดและแผนผังองค์ประกอบหัวฉีด แล้ว Angular จะแก้ไขมันอย่างไรเมื่อให้การพึ่งพา?
ใน Angular เมื่อแก้ไขโทเค็นเพื่อรับการขึ้นต่อกันสำหรับส่วนประกอบ/คำสั่ง Angular จะแก้ไขในสองขั้นตอน:
ElementInjector (พาเรนต์)ModuleInjector (พาเรนต์)กระบวนการมีดังต่อไปนี้ (อ้างถึง Multi-Level กฎของหัวฉีด - ความละเอียด):
เมื่อส่วนประกอบประกาศการขึ้นต่อกัน Angular จะพยายามตอบสนองการขึ้นต่อกันนั้นโดยใช้ ElementInjector ของตัวเอง
หากหัวฉีดของส่วนประกอบขาดผู้ให้บริการ ก็จะส่งคำขอไปยัง ElementInjector ของส่วนประกอบหลัก
คำขอเหล่านี้จะถูกส่งต่อไปจนกว่า Angular จะพบหัวฉีดที่สามารถจัดการคำขอหรือ ElementInjector บรรพบุรุษหมดได้
หาก Angular ไม่พบผู้ให้บริการใน ElementInjector ใดๆ Angular จะกลับไปยังองค์ประกอบที่มีการร้องขอและค้นหาลำดับชั้น ModuleInjector
หาก Angular ยังไม่พบผู้ให้บริการ จะทำให้เกิดข้อผิดพลาด
เพื่อจุดประสงค์นี้ Angular ขอแนะนำตัวผสานแบบพิเศษ
ตัวหัวฉีดผสานนั้นไม่มีค่า มันเป็นเพียงการผสมผสานระหว่างคำจำกัดความของมุมมองและองค์ประกอบ
คลาสหัวฉีด_ ใช้หัวฉีด {
ตัวสร้าง (มุมมองส่วนตัว: ViewData, elDef ส่วนตัว: NodeDef | null) {}
รับ (โทเค็น: ใด ๆ notFoundValue: ใด ๆ = Injector.THROW_IF_NOT_FOUND): ใด ๆ {
const AllowPrivateServices =
this.elDef ? (this.elDef.flags & NodeFlags.ComponentView) !== 0 : เท็จ;
กลับบริการ resolveDep (
this.view, this.elDef, อนุญาต PrivateServices,
{ธง: DepFlags.None, โทเค็น, tokenKey: tokenKey (โทเค็น)}, notFoundValue);
-
} เมื่อ Angular แก้ไขการพึ่งพา หัวฉีดผสานจะเป็นสะพานเชื่อมระหว่างแผนผังหัวฉีดองค์ประกอบและแผนผังโมดูลหัวฉีด เมื่อ Angular พยายามแก้ไขการขึ้นต่อกันบางอย่างในส่วนประกอบหรือคำสั่ง มันจะใช้ Merge injector เพื่อสำรวจแผนผังองค์ประกอบ Injector จากนั้นหากไม่พบการขึ้นต่อกัน ให้สลับไปที่แผนผังโมดูล Injector เพื่อแก้ไขการขึ้นต่อกัน
คลาส ViewContainerRef_ ใช้ ViewContainerData {
-
// แบบสอบถามสำหรับองค์ประกอบมุมมองพาเรนต์ injector รับ parentInjector (): Injector {
ปล่อยให้ดู = this._view;
ให้ elDef = this._elDef.parent;
ในขณะที่ (!elDef && ดู) {
elDef = viewParentEl (ดู);
ดู = view.parent!;
-
กลับมุมมอง ? new injector_(view, elDef) : new injector_(this._view, null);
-
} หัวฉีด สามารถสืบทอดได้ ซึ่งหมายความว่าหากหัวฉีดที่ระบุไม่สามารถแก้ไขการขึ้นต่อกันได้ ระบบจะขอให้หัวฉีดหลักแก้ไข อัลกอริธึมการแยกวิเคราะห์เฉพาะถูกนำไปใช้ในเมธอด resolveDep() :
ฟังก์ชันการส่งออก solveDep(
มุมมอง: ViewData, elDef: NodeDef, AllowPrivateServices: บูลีน, depDef: DepDef,
notFoundValue: any = Injector.THROW_IF_NOT_FOUND): ใด ๆ {
-
// mod1
-
// เอล1 mod2
-
//el2
-
// เมื่อร้องขอ el2.injector.get(token) ให้ตรวจสอบและส่งคืนค่าแรกที่พบในลำดับต่อไปนี้:
// - el2.injector.get (โทเค็น, ค่าเริ่มต้น)
// - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> อย่าตรวจสอบโมดูล
// - mod2.injector.get (โทเค็น, ค่าเริ่มต้น)
} หากเป็นส่วนประกอบ AppComponent รูทของเทมเพลตเช่น <child></child> จะมีมุมมองสามรายการใน Angular:
<!-- HostView_AppComponent -->
<แอปของฉัน></แอปของฉัน>
<!-- View_AppComponent -->
<เด็ก></เด็ก>
<!-- View_ChildComponent -->
เนื้อหาบางส่วน อาศัยกระบวนการแยกวิเคราะห์ อัลกอริธึมการแยกวิเคราะห์จะขึ้นอยู่กับลำดับชั้นการดู ดังแสดงในรูป:

หากโทเค็นบางตัวได้รับการแก้ไขในคอมโพเนนต์ลูก Angular จะ:
ดูที่หัวฉีดองค์ประกอบลูกก่อน โดยตรวจสอบ elRef.element.allProviders|publicProviders
จากนั้นวนซ้ำองค์ประกอบมุมมองพาเรนต์ทั้งหมด (1) และตรวจสอบผู้ให้บริการในองค์ประกอบหัวฉีด
หากองค์ประกอบมุมมองพาเรนต์ถัดไปมีค่าเท่ากับ null (2) ให้กลับไปที่ startView (3) และตรวจสอบ startView.rootData.elnjector (4)
เฉพาะในกรณีที่ไม่พบโทเค็น ให้ตรวจสอบ startView.rootData module.injector (5)
เป็นไปตามที่ Angular เมื่อสำรวจส่วนประกอบเพื่อแก้ไขการพึ่งพาบางอย่าง จะค้นหาองค์ประกอบหลักของมุมมองเฉพาะ แทนที่จะเป็นองค์ประกอบหลักขององค์ประกอบเฉพาะ องค์ประกอบหลักของมุมมองสามารถรับได้ทาง:
// สำหรับมุมมองส่วนประกอบ นี่คือองค์ประกอบโฮสต์ // สำหรับมุมมองแบบฝัง นี่คือดัชนีของโหนดหลักของฟังก์ชันการส่งออกคอนเทนเนอร์มุมมองที่มี viewParentEl(view: ViewData): NodeDef| โมฆะ {
const parentView = view.parent;
ถ้า (parentView) {
กลับ view.parentNodeDef !.parent;
} อื่น {
กลับเป็นโมฆะ;
-
} บทความนี้จะแนะนำโครงสร้างลำดับชั้นของ injectors ในเชิงมุมเป็นหลัก
การแนะนำแผนผังองค์ประกอบหัวฉีดส่วนใหญ่ใช้เพื่อแก้ปัญหาการสร้างอินสแตนซ์สองเท่าของโมดูลที่เกิดจากการแยกวิเคราะห์การฉีดขึ้นต่อกันและการโหลดโมดูลแบบ Lazy Loading หลังจากการแนะนำแผนผังองค์ประกอบหัวฉีด กระบวนการแยกวิเคราะห์การพึ่งพาของ Angular ก็ได้รับการปรับปรุงด้วย โดยจะจัดลำดับความสำคัญในการค้นหาการพึ่งพาของหัวฉีด เช่น องค์ประกอบหัวฉีดและองค์ประกอบมุมมองพาเรนต์ เฉพาะเมื่อไม่พบโทเค็นในองค์ประกอบหัวฉีดเท่านั้น จะถูกสอบถามถึงการพึ่งพาใน