เนื่องจากเฟรมเวิร์กส่วนหน้าได้รับการออกแบบ "สำหรับโปรเจ็กต์ส่วนหน้าขนาดใหญ่" Angular จึงมีการออกแบบมากมายที่ควรค่าแก่การอ้างอิงและการเรียนรู้ ซีรีส์นี้ใช้เพื่อศึกษาหลักการใช้งานของการออกแบบและฟังก์ชันเหล่านี้เป็นหลัก บทความนี้มุ่งเน้นไปที่คุณลักษณะที่ใหญ่ที่สุดของ Angular - dependency insert และแนะนำการออกแบบ dependency injection หลายระดับใน Angular [บทช่วยสอนที่เกี่ยวข้องที่แนะนำ: "บทช่วยสอนเชิงมุม"]
ในบทความก่อนหน้านี้ เราได้แนะนำ Injectot
injector ผู้ให้ Provider
และกลไกของหัวฉีดใน Angular ดังนั้นในแอปพลิเคชันเชิงมุม ส่วนประกอบและโมดูลจะแบ่งปันการพึ่งพาได้อย่างไร?
กระบวนการพึ่งพาการฉีดของส่วนประกอบและโมดูลแยกกันไม่ออกจากการออกแบบการฉีดพึ่งพาหลายระดับของ Angular
ดังที่เราได้กล่าวไว้ก่อนหน้านี้ injector ใน Angular สามารถสืบทอดได้และเป็นลำดับชั้น
ใน Angular มีลำดับชั้นของ injector สองลำดับ:
ModuleInjector
Module Injector: กำหนดค่า ModuleInjector ในลำดับชั้นนี้โดยใช้ @NgModule()
หรือ @Injectable()
คำอธิบายประกอบ ModuleInjector
ElementInjector
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 ก็ได้รับการปรับปรุงด้วย โดยจะจัดลำดับความสำคัญในการค้นหาการพึ่งพาของหัวฉีด เช่น องค์ประกอบหัวฉีดและองค์ประกอบมุมมองพาเรนต์ เฉพาะเมื่อไม่พบโทเค็นในองค์ประกอบหัวฉีดเท่านั้น จะถูกสอบถามถึงการพึ่งพาใน