资讯专栏INFORMATION COLUMN

angular源码分析之platformBrowserDynamic

zhoutao / 1712人阅读

摘要:生成项目后,中的代码这里调用了包中导出的函数这个函数是浏览器平台的工厂函数执行会返回浏览器平台的实例函数是通过函数创建的这个函数接收个参数父平台工厂函数平台名称服务提供商的数组顾名思义函数的作用是创建平台工厂的函数在框架被加

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(服务提供商的数组)

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_IDtoken的值

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_INITIALIZERtoken注入,然后遍历执行,所以也可以在应用中注入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]},

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/108828.html

相关文章

  • angular源码分析platformBrowserDynamic

    摘要:生成项目后,中的代码这里调用了包中导出的函数这个函数是浏览器平台的工厂函数执行会返回浏览器平台的实例函数是通过函数创建的这个函数接收个参数父平台工厂函数平台名称服务提供商的数组顾名思义函数的作用是创建平台工厂的函数在框架被加 cli生成项目后,main.ts中的代码 import { enableProdMode } from @angular/core; import { platf...

    FWHeart 评论0 收藏0
  • 试读angular源码第一章:开场与platformBrowserDynamic

    摘要:而且大部分人一听说就会本能地避开。至于启动项目,都是这一行开始的。应用是模块化的,它拥有自己的模块化系统,称作。开场来个自我介绍 angular 源码阅读 项目地址 文章地址 angular 版本:8.0.0-rc.4 欢迎看看我的类angular框架 关于为什么写这么一个项目 声明:仅仅为个人阅读源码的理解,不一定完全正确,还需要大佬的指点。 其实市面上很多关于 vue和react 的源码...

    RiverLi 评论0 收藏0
  • angular2初入眼帘-多components协作

    摘要:我们使用了模式书写,并引入了思想,这些以前只在里见到的设计,现在里也有体现,并且在本章中会着重讲解多的协作。如果之前写过,那对于这种书写方式一定无比熟悉。每次数据的变更,无论是还是,都将变化冒泡到,然后由再向下逐级推送各组件是否重绘。 前集回顾 在上一章里我们讲了如何在angular2下开发一个component(还没做的赶紧去学吧)。我们使用了Unidirectional Data ...

    dreamans 评论0 收藏0
  • angular2初入眼帘-搭个环境

    angular2是什么?我猜不容我赘述,各位一定略有耳闻,无论是曾经AngularJS的拥趸,亦或是React的粉丝,都或多或少的对她有过一点了解。未见其物、先闻其声,angular2在问世之前已经做足了宣传,想必诸位也一定被下面各种词汇所震慑,什么:TypeScript、 ES5、 ES6、 Dart、 Immutable、 Unidirectional Data Flow、 Reactive ...

    everfight 评论0 收藏0
  • angular2初入眼帘-了解component

    摘要:通过增加删除元素改变布局的。譬如和控制元素显示隐藏,或者改变元素行为的。譬如设计看过我之前介绍以手写依赖注入的朋友应该已经对行为驱动多少有些了解了。她有,并且包含了至少一个和一个标签。,将左边的事件传递给了右边的表达式通常就是事件处理函数。 前集回顾 在上一章里我们讲了如何为angular2搭建开发环境(还没搭起来的赶紧去看哦),并使之跑起来我们的第一个My First Angular...

    ixlei 评论0 收藏0

发表评论

0条评论

zhoutao

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<