成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Angular框架解讀--依賴注入的引導(dǎo)過(guò)程

開(kāi)發(fā) 前端
本文主要圍繞 Angular 中的最大特點(diǎn)——依賴注入,介紹 Angular 依賴注入在體系在應(yīng)用引導(dǎo)過(guò)程中的的設(shè)計(jì)和實(shí)現(xiàn)。

 [[412840]]

作為“為大型前端項(xiàng)目”而設(shè)計(jì)的前端框架,Angular 其實(shí)有許多值得參考和學(xué)習(xí)的設(shè)計(jì),本系列主要用于研究這些設(shè)計(jì)和功能的實(shí)現(xiàn)原理。本文主要圍繞 Angular 中的最大特點(diǎn)——依賴注入,介紹 Angular 依賴注入在體系在應(yīng)用引導(dǎo)過(guò)程中的的設(shè)計(jì)和實(shí)現(xiàn)。

多級(jí)依賴注入中,介紹了模塊注入器和元素注入器兩種層次結(jié)構(gòu)的注入器。那么,Angular 在引導(dǎo)過(guò)程中,又是如何初始化根模塊和入口組件的呢?

Angular 的引導(dǎo)過(guò)程

前面我們說(shuō)到,Angular 應(yīng)用在瀏覽器中引導(dǎo)時(shí),會(huì)創(chuàng)建瀏覽器平臺(tái),并引導(dǎo)根模塊:

  1. platformBrowserDynamic().bootstrapModule(AppModule); 

引導(dǎo)根模塊

根模塊 AppModule

在 Angular 中,每個(gè)應(yīng)用有至少一個(gè) Angular 模塊,根模塊就是你用來(lái)引導(dǎo)此應(yīng)用的模塊,它通常命名為 AppModule。

當(dāng)你使用 Angular CLI 命令 ng new 生成一個(gè)應(yīng)用時(shí),其默認(rèn)的 AppModule 是這樣的:

  1. import { BrowserModule } from '@angular/platform-browser'
  2. import { NgModule } from '@angular/core'
  3.  
  4. import { AppComponent } from './app.component'
  5.  
  6. @NgModule({ 
  7.   declarations: [ 
  8.     AppComponent 
  9.   ], 
  10.   imports: [ 
  11.     BrowserModule 
  12.   ], 
  13.   providers: [], 
  14.   bootstrap: [AppComponent] 
  15. }) 
  16. export class AppModule { } 

引導(dǎo)根模塊的過(guò)程

我們來(lái)看看平臺(tái)層引導(dǎo)根模塊的過(guò)程中都做了些什么:

  1. @Injectable() 
  2. export class PlatformRef { 
  3.   ... 
  4.  
  5.   bootstrapModuleFactory<M>(moduleFactory: NgModuleFactory<M>, options?: BootstrapOptions): 
  6.       Promise<NgModuleRef<M>> { 
  7.     // 由于實(shí)例化模塊時(shí),會(huì)需要?jiǎng)?chuàng)建一些提供者,所以這里需要在實(shí)例化模塊之前創(chuàng)建 NgZone 
  8.     // 因此,這里創(chuàng)建了一個(gè)僅包含新 NgZone 的微型父注入器,并將其作為父?jìng)鬟f給 NgModuleFactory 
  9.     const ngZoneOption = options ? options.ngZone : undefined; 
  10.     const ngZoneEventCoalescing = (options && options.ngZoneEventCoalescing) || false
  11.     const ngZoneRunCoalescing = (options && options.ngZoneRunCoalescing) || false
  12.     const ngZone = getNgZone(ngZoneOption, {ngZoneEventCoalescing, ngZoneRunCoalescing}); 
  13.     const providers: StaticProvider[] = [{provide: NgZone, useValue: ngZone}]; 
  14.     // ApplicationRef 將在 Angular zone 之外創(chuàng)建 
  15.     return ngZone.run(() => { 
  16.       // 在 ngZone.run 中創(chuàng)建 ngZoneInjector,以便在 Angular zone 中創(chuàng)建所有實(shí)例化的服務(wù) 
  17.       const ngZoneInjector = Injector.create( 
  18.           {providers: providers, parent: this.injector, name: moduleFactory.moduleType.name}); 
  19.       const moduleRef = <InternalNgModuleRef<M>>moduleFactory.create(ngZoneInjector); 
  20.       const exceptionHandler: ErrorHandler|null = moduleRef.injector.get(ErrorHandler, null); 
  21.       if (!exceptionHandler) { 
  22.         throw new Error('No ErrorHandler. Is platform module (BrowserModule) included?'); 
  23.       } 
  24.       ... 
  25.       return _callAndReportToErrorHandler(exceptionHandler, ngZone!, () => { 
  26.         const initStatus: ApplicationInitStatus = moduleRef.injector.get(ApplicationInitStatus); 
  27.         initStatus.runInitializers(); 
  28.         return initStatus.donePromise.then(() => { 
  29.           ... 
  30.           // 引導(dǎo)模塊 
  31.           this._moduleDoBootstrap(moduleRef); 
  32.           return moduleRef; 
  33.         }); 
  34.       }); 
  35.     }); 
  36.   } 
  37.  
  38.   bootstrapModule<M>( 
  39.       moduleType: Type<M>, 
  40.       compilerOptions: (CompilerOptions&BootstrapOptions)| 
  41.       Array<CompilerOptions&BootstrapOptions> = []): Promise<NgModuleRef<M>> { 
  42.     const options = optionsReducer({}, compilerOptions); 
  43.     // 編譯并創(chuàng)建 @NgModule 的實(shí)例 
  44.     return compileNgModuleFactory(this.injector, options, moduleType) 
  45.         .then(moduleFactory => this.bootstrapModuleFactory(moduleFactory, options)); 
  46.   } 
  47.  
  48.   private _moduleDoBootstrap(moduleRef: InternalNgModuleRef<any>): void { 
  49.     const appRef = moduleRef.injector.get(ApplicationRef) as ApplicationRef; 
  50.     // 引導(dǎo)應(yīng)用程序 
  51.     if (moduleRef._bootstrapComponents.length > 0) { 
  52.       // 在應(yīng)用程序的根級(jí)別引導(dǎo)新組件 
  53.       moduleRef._bootstrapComponents.forEach(f => appRef.bootstrap(f)); 
  54.     } else if (moduleRef.instance.ngDoBootstrap) { 
  55.       moduleRef.instance.ngDoBootstrap(appRef); 
  56.     } else { 
  57.       ... 
  58.     } 
  59.     this._modules.push(moduleRef); 
  60.   } 

根模塊引導(dǎo)時(shí),除了編譯并創(chuàng)建 AppModule 的實(shí)例,還會(huì)創(chuàng)建 NgZone,關(guān)于 NgZone 的請(qǐng)參考。在編譯和創(chuàng)建 AppModule 的過(guò)程中,便會(huì)創(chuàng)建 ApplicationRef ,即 Angular 應(yīng)用程序。

引導(dǎo) Angular 應(yīng)用程序

前面在引導(dǎo)根模塊過(guò)程中,創(chuàng)建了 Angular 應(yīng)用程序之后,便會(huì)在應(yīng)用程序的根級(jí)別引導(dǎo)新組件:

  1. // 在應(yīng)用程序的根級(jí)別引導(dǎo)新組件 
  2. moduleRef._bootstrapComponents.forEach(f => appRef.bootstrap(f)); 

我們來(lái)看看這個(gè)過(guò)程會(huì)發(fā)生什么。

應(yīng)用程序 ApplicationRef

一個(gè) Angular 應(yīng)用程序,提供了以下的能力:

  1. @Injectable() 
  2. export class ApplicationRef { 
  3.   // 獲取已注冊(cè)到該應(yīng)用程序的組件類型的列表 
  4.   public readonly componentTypes: Type<any>[] = []; 
  5.   // 獲取已注冊(cè)到該應(yīng)用程序的組件的列表 
  6.   public readonly components: ComponentRef<any>[] = []; 
  7.   // 返回一個(gè) Observable,指示應(yīng)用程序何時(shí)穩(wěn)定或不穩(wěn)定 
  8.   // 如果在應(yīng)用程序引導(dǎo)時(shí),引導(dǎo)任何種類的周期性異步任務(wù),則該應(yīng)用程序?qū)⒂肋h(yuǎn)不會(huì)穩(wěn)定(例如輪詢過(guò)程) 
  9.   public readonly isStable!: Observable<boolean>; 
  10.  
  11.   constructor( 
  12.       private _zone: NgZone, private _injector: Injector, private _exceptionHandler: ErrorHandler, 
  13.       private _componentFactoryResolver: ComponentFactoryResolver, 
  14.       private _initStatus: ApplicationInitStatus) { 
  15.         // 創(chuàng)建時(shí),主要進(jìn)行兩件事: 
  16.         // 1. 宏任務(wù)結(jié)束后,檢測(cè)視圖是否需要更新。 
  17.         // 2. 在 Angular Zone 之外創(chuàng)建對(duì) onStable 的預(yù)訂,以便在 Angular Zone 之外運(yùn)行回調(diào)。 
  18.   } 
  19.   // 在應(yīng)用程序的根級(jí)別引導(dǎo)新組件 
  20.   bootstrap<C>(componentOrFactory: ComponentFactory<C>|Type<C>, rootSelectorOrNode?: string|any): 
  21.       ComponentRef<C> {} 
  22.   // 調(diào)用此方法以顯式處理更改檢測(cè)及其副作用 
  23.   tick(): void {} 
  24.   // 關(guān)聯(lián)視圖,以便對(duì)其進(jìn)行臟檢查,視圖銷毀后將自動(dòng)分離 
  25.   attachView(viewRef: ViewRef): void {} 
  26.   // 再次從臟檢查中分離視圖 
  27.   detachView(viewRef: ViewRef): void {} 

那么,我們來(lái)看看 bootstrap() 過(guò)程中,Angular 都做了些什么。

在應(yīng)用程序的根級(jí)別引導(dǎo)根組件

將新的根組件引導(dǎo)到應(yīng)用程序中時(shí),Angular 將指定的應(yīng)用程序組件安裝到由 componentType 的選擇器標(biāo)識(shí)的 DOM 元素上,并引導(dǎo)自動(dòng)更改檢測(cè)以完成組件的初始化。

  1. @Injectable() 
  2. export class ApplicationRef { 
  3.   bootstrap<C>(componentOrFactory: ComponentFactory<C>|Type<C>, rootSelectorOrNode?: string|any): 
  4.       ComponentRef<C> { 
  5.     ... 
  6.     // 如果未與其他模塊綁定,則創(chuàng)建與當(dāng)前模塊關(guān)聯(lián)的工廠 
  7.     const ngModule = 
  8.         isBoundToModule(componentFactory) ? undefined : this._injector.get(NgModuleRef); 
  9.     const selectorOrNode = rootSelectorOrNode || componentFactory.selector; 
  10.     // 創(chuàng)建組件 
  11.     const compRef = componentFactory.create(Injector.NULL, [], selectorOrNode, ngModule); 
  12.     const nativeElement = compRef.location.nativeElement; 
  13.     // 創(chuàng)建可測(cè)試服務(wù)掛鉤 
  14.     const testability = compRef.injector.get(Testability, null); 
  15.     const testabilityRegistry = testability && compRef.injector.get(TestabilityRegistry); 
  16.     if (testability && testabilityRegistry) { 
  17.       testabilityRegistry.registerApplication(nativeElement, testability); 
  18.     } 
  19.     // 組件銷毀時(shí),銷毀關(guān)聯(lián)視圖以及相關(guān)的服務(wù) 
  20.     compRef.onDestroy(() => { 
  21.       this.detachView(compRef.hostView); 
  22.       remove(this.components, compRef); 
  23.       if (testabilityRegistry) { 
  24.         testabilityRegistry.unregisterApplication(nativeElement); 
  25.       } 
  26.     }); 
  27.     // 加載組件,包括關(guān)聯(lián)視圖、監(jiān)聽(tīng)變更等 
  28.     this._loadComponent(compRef); 
  29.     ... 
  30.     return compRef; 
  31.   } 

在創(chuàng)建根組件的過(guò)程中,會(huì)關(guān)聯(lián) DOM 元素視圖、添加對(duì)狀態(tài)變更的檢測(cè)機(jī)制。

根組件是一個(gè)入口組件,Angular CLI 創(chuàng)建的默認(rèn)應(yīng)用只有一個(gè)組件 AppComponent ,Angular 會(huì)在引導(dǎo)過(guò)程中把它加載到 DOM 中。

在根組件的創(chuàng)建過(guò)程中,通常會(huì)根據(jù)根組件中引用到的其他組件,觸發(fā)一系列組件的創(chuàng)建并形成組件樹(shù)。大多數(shù)應(yīng)用只有一個(gè)組件樹(shù),并且只從一個(gè)根組件開(kāi)始引導(dǎo)。

創(chuàng)建組件過(guò)程

Angular 中創(chuàng)建組件的過(guò)程如下:

  1. 當(dāng) Angular 創(chuàng)建組件類的新實(shí)例時(shí),它會(huì)通過(guò)查看該組件類的構(gòu)造函數(shù),來(lái)決定該組件依賴哪些服務(wù)或其它依賴項(xiàng)。
  2. 當(dāng) Angular 發(fā)現(xiàn)某個(gè)組件依賴某個(gè)服務(wù)時(shí),它會(huì)首先檢查是否該注入器中已經(jīng)有了那個(gè)服務(wù)的任何現(xiàn)有實(shí)例。如果所請(qǐng)求的服務(wù)尚不存在,注入器就會(huì)使用以前注冊(cè)的服務(wù)提供者來(lái)制作一個(gè),并把它加入注入器中,然后把該服務(wù)返回給 Angular。
  3. 當(dāng)所有請(qǐng)求的服務(wù)已解析并返回時(shí),Angular 可以用這些服務(wù)實(shí)例為參數(shù),調(diào)用該組件的構(gòu)造函數(shù)。

Angular 會(huì)在執(zhí)行應(yīng)用時(shí)創(chuàng)建注入器,第一個(gè)注入器是根注入器,創(chuàng)建于引導(dǎo)過(guò)程中。借助注入器繼承機(jī)制,可以把全應(yīng)用級(jí)的服務(wù)注入到這些組件中。

到這里,Angular 分別完成了根模塊、根組件和組件樹(shù)的引導(dǎo)過(guò)程,通過(guò)編譯器則可以將組件和視圖渲染到頁(yè)面上。

總結(jié)

在應(yīng)用程序的引導(dǎo)過(guò)程中,Angular 采取了以下步驟來(lái)加載我們的第一個(gè)視圖:

  1. index.html 
  2. Main.ts 

本文我們重點(diǎn)從根模塊的引導(dǎo)過(guò)程開(kāi)始,介紹了引導(dǎo) Angular 應(yīng)用程序、引導(dǎo)根組件、組件的創(chuàng)建等過(guò)程。至于組件樹(shù)的創(chuàng)建和渲染,則可以參考 編譯器 相關(guān)的內(nèi)容。

 

責(zé)任編輯:張燕妮 來(lái)源: Here. There.
相關(guān)推薦

2014-07-08 14:05:48

DaggerAndroid依賴

2009-05-21 16:41:22

GuiceJava依賴注入

2023-10-07 08:35:07

依賴注入Spring

2025-01-02 00:00:00

2022-12-29 08:54:53

依賴注入JavaScript

2015-06-17 16:01:30

ASP.NET

2023-06-28 08:16:50

Autofac應(yīng)用程序

2015-09-02 11:22:36

JavaScript實(shí)現(xiàn)思路

2011-05-31 10:00:21

Android Spring 依賴注入

2011-03-29 09:51:58

GuiceIOC

2019-12-20 14:19:47

Linux操作系統(tǒng)引導(dǎo)

2023-07-11 09:14:12

Beanquarkus

2024-05-27 00:13:27

Go語(yǔ)言框架

2017-08-16 16:00:05

PHPcontainer依賴注入

2022-04-11 09:02:18

Swift依賴注

2024-12-30 12:00:00

.NET Core依賴注入屬性注入

2009-12-10 19:02:30

2009-10-09 17:51:15

RHEL引導(dǎo)故障

2016-03-21 17:08:54

Java Spring注解區(qū)別

2016-12-28 09:30:37

Andriod安卓平臺(tái)依賴注入
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 青青草视频免费观看 | 国产精品国产三级国产aⅴ入口 | 极品粉嫩国产48尤物在线播放 | 中日字幕大片在线播放 | 欧美一区二区三区在线观看 | 国产激情网站 | 国产精品免费观看 | 9久9久| 久久蜜桃资源一区二区老牛 | 久久精品久久综合 | 日韩一二区 | 青青草综合网 | 亚洲综合色 | 日韩精品一区二区在线 | 欧美激情精品久久久久久免费 | 免费观看黄a一级视频 | 国内精品视频一区二区三区 | 日韩国产欧美一区 | 色偷偷噜噜噜亚洲男人 | 欧美一区二区免费 | 热re99久久精品国产99热 | 欧美一区二不卡视频 | 两性午夜视频 | 国产www.| 蜜臀网站| 欧美一区二区三区视频 | 亚洲aⅴ | 欧美一区二区在线播放 | 亚洲一区二区在线电影 | 香蕉久久久久久 | 国产精品美女久久久久aⅴ国产馆 | 91pron在线| 性高湖久久久久久久久3小时 | 国产做a爱片久久毛片 | 日本在线视频中文字幕 | 亚洲精品2 | 国产福利在线 | 中文字幕免费在线 | 一区二区国产精品 | 日韩精品一区在线观看 | 久久99深爱久久99精品 |