cli生成项目后,main.ts中的代码
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
看第一个参数
platformCoreDynamic
:
export const platformCoreDynamic = createPlatformFactory(platformCore, 'coreDynamic', [
{provide: COMPILER_OPTIONS, useValue: {}, multi: true},
{provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS]},
]);
第一个参数也是通过
createPlatformFactory
函数创建的一个工厂函数,这里执行的时候又传入了三个参数
platformCore
,
'coreDynamic'
和一个提供商数组
第一个参数
platformCore
:
export const platformCore = createPlatformFactory(null, 'core', _CORE_PLATFORM_PROVIDERS);
又是通过
createPlatformFactory
函数创建的… ,但好在没有在继续传入父平台作为参数,所以应用初始化时执行的第一个函数就是这个了
这里有点绕,屡一下函数的执行过程:
-
createPlatformFactory(null, 'core', _CORE_PLATFORM_PROVIDERS)
执行返回
platformCore
函数 -
createPlatformFactory(platformCore, 'coreDynamic', [...])
执行返回
platformCoreDynamic
函数 -
createPlatformFactory(platformCoreDynamic, 'browserDynamic', INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS)
执行返回
platformBrowserDynamic
函数 -
platformBrowserDynamic()
执行返回平台实例
要注意到这里创建的都是工厂函数,而不是平台实例,在angular框架被加载后,就会开始执行,此时应用还没有正式启动
在执行
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]},