bootstrapModule前干的事情

一個最簡單的Angular程序

在了解Angular2啟動過程之前,我們先看一段代碼:

import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { NgModule, Component}  from "@angular/core";
import { BrowserModule }  from "@angular/platform-browser";

// 定義Component
@Component({
    selector: "my-app",
    template: "<div></div>"
})
export class AppComponent {}

// 定義Module
@NgModule({
    imports: [
        BrowserModule
    ],
    declarations: [
        AppComponent
    ],
    bootstrap: [ AppComponent ]
})
export class AppModule { }

// 啟動Angular程序
platformBrowserDynamic().bootstrapModule(AppModule);

這一段代碼主要有四個部分組成:
1、引用Angular相關(guān)的類
2、定義Component(什么是Component(todo:下次分析),@Component是什么(在這里))
3、定義了一個Module(什么是Module(todo:下次分析),@Module是什么(在這里))
4、調(diào)用Angular的啟動函數(shù),實現(xiàn)啟動功能。
從代碼我們可以發(fā)現(xiàn),啟動過程實際上是分成了兩大步驟的。
1、調(diào)用platformBrowserDynamic()方法
2、調(diào)用bootstrapModule(AppModule)方法(在這里)

platformBrowserDynamic都干了什么

要想知道platformBrowserDynamic都干了啥,我們可以查看他的代碼:

export const platformBrowserDynamic = createPlatformFactory(
    platformCoreDynamic, 'browserDynamic', INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS);

可以看出這個方法是通過調(diào)用createPlatformFactory方法得到的,生成的時候會傳入三個參數(shù),其中有第二個參數(shù)是字符串,我們看看其它兩個參數(shù)都是什么。
第一個參數(shù):

export const platformCoreDynamic = createPlatformFactory(platformCore, 'coreDynamic', [
  {provide: COMPILER_OPTIONS, useValue: {}, multi: true},
  {provide: CompilerFactory, useClass: JitCompilerFactory},
  {provide: PLATFORM_INITIALIZER, useValue: _initReflector, multi: true},
]);

第三個參數(shù):

export const INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS: Provider[] = [
  INTERNAL_BROWSER_PLATFORM_PROVIDERS,
  {
    provide: COMPILER_OPTIONS,
    useValue: {providers: [{provide: ResourceLoader, useClass: ResourceLoaderImpl}]},
    multi: true
  },
];

發(fā)現(xiàn)platformCoreDynamic也是通過createPlatformFactory方法得到的,調(diào)用的時候又引入了一個新的參數(shù):platformCore,它初始化的代碼為:

function _reflector(): Reflector {
  return reflector;
}

const _CORE_PLATFORM_PROVIDERS: Provider[] = [
  PlatformRef_,
  {provide: PlatformRef, useExisting: PlatformRef_},
  {provide: Reflector, useFactory: _reflector, deps: []},
  {provide: ReflectorReader, useExisting: Reflector},
  TestabilityRegistry,
  Console,
];

/**
 * This platform has to be included in any other platform
 *
 * @experimental
 */
export const platformCore = createPlatformFactory(null, 'core', _CORE_PLATFORM_PROVIDERS);

可以看出platformCore初始化的時候也是調(diào)用的createPlatformFactory。
至此我們可以知道platformBrowserDynamic的關(guān)系圖:

platformBrowserDynamic
     |
     +---> platformCoreDynamic
                |
                +---> platformCore

接下來我們分析最為關(guān)鍵的createPlatformFactory方法。

export function createPlatformFactory(
    parentPlaformFactory: (extraProviders?: Provider[]) => PlatformRef, name: string,
    providers: Provider[] = []): (extraProviders?: Provider[]) => PlatformRef {
  const marker = new OpaqueToken(`Platform: ${name}`);
  return (extraProviders: Provider[] = []) => {
    if (!getPlatform()) {
      if (parentPlaformFactory) {
        parentPlaformFactory(
            providers.concat(extraProviders).concat({provide: marker, useValue: true}));
      } else {
        createPlatform(ReflectiveInjector.resolveAndCreate(
            providers.concat(extraProviders).concat({provide: marker, useValue: true})));
      }
    }
    return assertPlatform(marker);
  };
}

可以看出在createPlatformFactory方法中,只是簡單的返回了一個內(nèi)部方法。當我們調(diào)用platformBrowserDynamic()時,實際就是調(diào)用這個內(nèi)部方法。其實這個內(nèi)部方法也比較簡單,主要邏輯為:
1、判斷是否已經(jīng)創(chuàng)建過了。
2、判斷是否有父Factory。
3、如果有父Factory就把調(diào)用Factory時傳入的Provider和調(diào)用createPlatformFactory傳入的Provider合并,然后調(diào)用父Factory。
4、如果沒有父Factory,先創(chuàng)建一個Injector,然后去創(chuàng)建platform。
由之前的關(guān)系圖可以知道,當我們調(diào)用platformBrowserDynamic,實際調(diào)用的是platformCore,Provider就是各個createPlatformFactory傳入的第三個參數(shù),通過這些Provider創(chuàng)建了一個Injector,并通過Injector創(chuàng)建了platform(看這里)。
我們在看看創(chuàng)建Platform的過程:

export function createPlatform(injector: Injector): PlatformRef {
  if (_platform && !_platform.destroyed) {
    throw new Error(
        'There can be only one platform. Destroy the previous one to create a new one.');
  }
  _platform = injector.get(PlatformRef);
  const inits: Function[] = <Function[]>injector.get(PLATFORM_INITIALIZER, null);
  if (inits) inits.forEach(init => init());
  return _platform;
}

在這段代碼使用到了Injector的特性來創(chuàng)建的(看這里)。創(chuàng)建完以后會獲取所有名為PLATFORM_INITIALIZER的Provider,然后調(diào)用它。

至此platformBrowserDynamic()執(zhí)行過程已經(jīng)全部理清楚了,在這個過程中會創(chuàng)建Injector和platform,其中Injector是依賴注入的關(guān)鍵(看這里)。
在分析的過程中,發(fā)現(xiàn)可以通過定義一個PLATFORM_INITIALIZER名稱的Provider實現(xiàn)在初始化Platform后執(zhí)行代碼。示例代碼:

function test(){
   console.log("This is a test!");
}

platformBrowserDynamic([{provide: PLATFORM_INITIALIZER, useValue: test, multi: true}]).bootstrapModule(AppModule);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、angularjs的幾大特性是什么? 雙向數(shù)據(jù)綁定、依賴注入、模板、指令、MVC/MVVM 2、列舉幾種常見的...
    2e9a10d418ab閱讀 1,457評論 0 10
  • Angular面試題 一、ng-show/ng-hide與ng-if的區(qū)別? 第一點區(qū)別是,ng-if在后面表達式...
    w_zhuan閱讀 5,704評論 0 26
  • 1、angularjs的幾大特性是什么? 雙向數(shù)據(jù)綁定、依賴注入、模板、指令、MVC/MVVM 2、列舉幾種常見的...
    秀才JaneBook閱讀 1,601評論 0 22
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,533評論 19 139
  • 11月18日,陰雨綿綿的一天。 今天下午,給三年級的孩子上了一堂作文課。這堂課重點是訓(xùn)練心理描寫,讓作文學會思考。...
    呂文娟閱讀 618評論 0 0

友情鏈接更多精彩內(nèi)容