cli生成項目後,main.ts中的代碼bootstrap
import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; if (environment.production) { enableProdMode(); } platformBrowserDynamic().bootstrapModule(AppModule).catch(err => console.error(err));
這裏調用了@angular/platform-browser-dynamic
包中導出的platformBrowserDynamic
函數,這個函數是瀏覽器平臺的工廠函數,執行會返回瀏覽器平臺的實例數組
export const platformBrowserDynamic = createPlatformFactory(platformCoreDynamic, 'browserDynamic', INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS);
platformBrowserDynamic
函數是經過createPlatformFactory
函數建立的,這個函數接收3個參數,parentPlatformFactory
(父平臺工廠函數),name
(平臺名稱),providers
(服務提供商的數組)
<!-- 顧名思義,createPlatformFactory
函數的做用是建立平臺工廠的函數 -->瀏覽器
export function createPlatformFactory( parentPlatformFactory: ((extraProviders?: StaticProvider[]) => PlatformRef) | null, name: string, providers: StaticProvider[] = []): (extraProviders?: StaticProvider[]) => PlatformRef { const desc = `Platform: ${name}`; const marker = new InjectionToken(desc); return (extraProviders: StaticProvider[] = []) => { let platform = getPlatform(); if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) { if (parentPlatformFactory) { parentPlatformFactory( providers.concat(extraProviders).concat({provide: marker, useValue: true})); } else { const injectedProviders: StaticProvider[] = providers.concat(extraProviders).concat({provide: marker, useValue: true}); createPlatform(Injector.create({providers: injectedProviders, name: desc})); } } return assertPlatform(marker); }; }
在angular框架被加載後,會執行這個函數,並傳入了三個參數分別爲 platformCoreDynamic
, 'browserDynamic'
, INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS
app
看第一個參數platformCoreDynamic
:框架
export const platformCoreDynamic = createPlatformFactory(platformCore, 'coreDynamic', [ {provide: COMPILER_OPTIONS, useValue: {}, multi: true}, {provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS]}, ]);
第一個參數也是經過createPlatformFactory
函數建立的一個工廠函數,這裏執行的時候又傳入了三個參數platformCore
,'coreDynamic'
和一個提供商數組ide
第一個參數platformCore
:函數
export const platformCore = createPlatformFactory(null, 'core', _CORE_PLATFORM_PROVIDERS);
又是經過createPlatformFactory
函數建立的... ,但好在沒有在繼續傳入父平臺做爲參數,因此應用初始化時執行的第一個函數就是這個了code
這裏有點繞,屢一下函數的執行過程:orm
createPlatformFactory(null, 'core', _CORE_PLATFORM_PROVIDERS)
執行返回platformCore
函數createPlatformFactory(platformCore, 'coreDynamic', [...])
執行返回platformCoreDynamic
函數createPlatformFactory(platformCoreDynamic, 'browserDynamic', INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS)
執行返回platformBrowserDynamic
函數platformBrowserDynamic()
執行返回平臺實例要注意到這裏建立的都是工廠函數,而不是平臺實例,在angular框架被加載後,就會開始執行,此時應用尚未正式啓動token
在執行platformBrowserDynamic()
後,應用開始啓動,實例化core
平臺(這裏的調用順序就不貼出來了,雖然工廠函數的調用順序是platformBrowserDynamic
->platformCoreDynamic
->platformCore
,可是實例化的只有core
平臺)
coreDynamic
平臺和browserDynamic
平臺的工廠函數並非建立子平臺的實例,而是添加服務提供商,被實例化的只有一個平臺實例,只不過會改變PLATFORM_ID
token的值
core
平臺實例化以前,首先建立了應用的根注入器
createPlatform(Injector.create({providers: injectedProviders, name: desc}));
在core
平臺實例化過程當中,又經過子平臺工廠函數的參數和區域變量,傳入了一些服務提供商,而後將這些提供商統一註冊到了注入器中:
// 這裏的變量名是我命名的不是源碼中的名字,用以區分各個平臺下注冊的提供商 export const browserDynamic_PROVIDERS: StaticProvider[] = [ {provide: PLATFORM_ID, useValue: PLATFORM_BROWSER_ID}, {provide: PLATFORM_INITIALIZER, useValue: initDomAdapter, multi: true}, {provide: PlatformLocation, useClass: BrowserPlatformLocation, deps: [DOCUMENT]}, {provide: DOCUMENT, useFactory: _document, deps: []}, { provide: COMPILER_OPTIONS, useValue: {providers: [{provide: ResourceLoader, useClass: ResourceLoaderImpl, deps: []}]}, multi: true }, {provide: PLATFORM_ID, useValue: PLATFORM_BROWSER_ID} ]; export const coreDynamic_PROVIDERS: StaticProvider[] = [ {provide: COMPILER_OPTIONS, useValue: {}, multi: true}, {provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS]} ]; export const core_PROVIDERS: StaticProvider[] = [ // Set a default platform name for platforms that don't set it explicitly. {provide: PLATFORM_ID, useValue: 'unknown'}, {provide: PlatformRef, deps: [Injector]}, {provide: TestabilityRegistry, deps: []}, {provide: Console, deps: []}, ]
而後進行初始化的操做,包括BrowserDomAdapter
(DOM適配器)和BrowserGetTestability
export function createPlatform(injector: Injector): PlatformRef { if (_platform && !_platform.destroyed && !_platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) { throw new Error( 'There can be only one platform. Destroy the previous one to create a new one.'); } _platform = injector.get(PlatformRef); // 初始化操做 browserDynamic平臺下的PLATFORM_INITIALIZER服務 const inits = injector.get(PLATFORM_INITIALIZER, null); if (inits) inits.forEach((init: any) => init()); return _platform; }
這裏初始化操做是經過PLATFORM_INITIALIZER
token注入,而後遍歷執行,因此也能夠在應用中注入PLATFORM_INITIALIZER
,而後執行一些啓動時的自定義的任務.
到這裏,core
平臺的實例化就完成了.
ps:
除了platform-browser-dynamic
以外還有platform-browser
模塊,這兩個模塊的區別是編譯方式的不一樣,platform-browser-dynamic
模塊提供jit編譯,也就是說編譯在瀏覽器內完成,而platform-browser
模塊提供aot編譯,編譯在本地完成.
在代碼層面上來講,platform-browser
模塊下core
平臺的子平臺只有browser
平臺,而platform-browser-dynamic
模塊下,core
平臺的子平臺包含coreDynamic
平臺和browserDynamic
平臺,並添加了額外的服務提供商
{ provide: COMPILER_OPTIONS, useValue: {providers: [{provide: ResourceLoader, useClass: ResourceLoaderImpl, deps: []}]}, multi: true }, {provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS]},