Angular 2 - 提供商实际上如何运作?

时间:2016-04-18 18:30:02

标签: javascript angular

我一直在经历"英雄"官方Angular 2页面上的教程,当我开始路由时,有些事情没有意义。它是关于提供者的。

有问题的部分表示如下。我的主要组件如下所示:

/* app.components */
import {Component} from 'angular2/core';
import {HeroesComponent} from './heroes.component';
import {HeroService} from './hero.service';

@Component({
    selector: 'my-app',
    template: `
        <h1>{{title}}</h1>
        <my-heroes></my-heroes>
    `
    directives: [HeroesComponent],
    providers: [HeroService]

})
export class AppComponent {
    title = 'Tour of Heroes';
    constructor(private _heroService: HeroService) {}
}

并且英雄组件看起来像这样:

/* heroes.component */
import {Component} from 'angular2/core';
import {Hero} from './hero';
import {HeroDetailComponent} from './hero-detail.component';
import {HeroService} from './hero.service';
import {OnInit} from 'angular2/core';

@Component({
    selector: 'my-heroes',
    directives: [HeroDetailComponent],
    template: `
        <h2>My Heroes</h2>
        <ul class="heroes">
            <li *ngFor="#hero of heroes" [class.selected] = "hero === selectedHero" (click)="onSelect(hero)">
                <span class="badge"> {{hero.id}} </span> {{hero.name}}
            </li>
        </ul>
        <my-hero-detail [hero]="selectedHero"></my-hero-detail>
        `
})
export class HeroesComponent implements OnInit {
    heroes: Hero[];
    selectedHero: Hero;
    ngOnInit() {
        this.getHeroes();
    }
    constructor(private _heroService: HeroService) {    }

    getHeroes() {
        this._heroService.getHeroes().then(heroes => this.heroes = heroes);
    }

    onSelect(hero: Hero) {
        this.selectedHero = hero;
    }

}

好的,我的问题是:为了实现这一点,我需要在两个文件中导入import {HeroService} from './hero.service';。但是,providers: [HeroService]只是@Component app.components的一部分。我不需要在heroes.component中编写这段代码。 heroes.component如何知道选择哪个提供商?它是继承自app.components吗?如果是这样,为什么我必须在两个文件中都写这个:import {HeroService} from './hero.service';?为什么不在app.components?这两个类也具有相同的constructor。我不知道这里发生了什么,所以提前感谢任何解释。

4 个答案:

答案 0 :(得分:0)

注射器是分层的。在bootstrap()中初始化根提供程序,然后为每个组件创建另一个子注入器,从而生成一个模仿DOM中组件的结构。

当Angular实例化一个类(服务,组件,管道......)时,它会请求一个DI实例,DI也会尝试解析构造函数参数。这是递归完成的,直到不需要进一步的依赖来解析,然后返回实例。

从最近的注射器请求实例。如果注射器没有类型的提供者(或其他键,如字符串或OpaqueToken),请求将被转发到父注射器,直到找到提供者或达到根注射器。

有关详细信息,请参阅https://angular.io/docs/ts/latest/api/core/Directive-decorator.html

答案 1 :(得分:0)

这与Angular2的“分层注入器”功能相关联。这些注射器链接到组件并遵循相同的树。

子组件的注入器是父组件的子注入器。如果未在当前注入器中找到提供者,则会将其查找到父提供者...

有关详细信息,请参阅此问题:

答案 2 :(得分:0)

是的,它是继承的,注入器是分层的。查看此博客post和官方documentation

答案 3 :(得分:0)

在研究了 Angular-2 的一些文档后,我分享了我对dependency-injection and providers的了解,这些知识可以帮助某些人。

依赖注入是分层的 依赖注入是一种重要的应用程序设计模式。 Angular有自己的依赖注入框架,如果没有它,我们真的无法构建一个Angular应用程序。

依赖关系是注入器范围内的单例。在我们的示例中,HeroService及其AppComponent个孩子共享了一个HeroComponent个实例。

在您的示例中,AppComponent是“英雄”功能区域的根组件。它管理该区域的所有子组件。您的HeroService可能会公开一个返回英雄数据的getHeroes方法,但其消费者都不需要知道这一点。

  

服务只不过是Angular 2中的一个类。它仍然存在   只有一个类,直到我们用Angular注册它   喷射器。

这就是配置进样器的原因。我们不必创建Angular注入器。 Angular在引导过程中为我们创建了一个应用程序范围的注入器。我们必须通过注册创建应用程序所需服务的提供程序来配置注入器。我们可以在引导期间注册提供程序。像:

bootstrap(AppComponent,
         [HeroService]); // DISCOURAGED (but works)

注射器现在知道我们的HeroService。我们HeroService的一个实例将可用于整个应用程序的注入。

首选方法是在应用程序组件中注册应用程序提供程序。因为HeroService用于英雄功能区域 - 而不是其他地方 - 注册它的理想位置是在顶层HeroesComponent

在组件中注册提供商

providers:[HeroService], // in your app.component that registers the HeroService

仔细查看providers元数据的@Component部分。

  

HeroService的一个实例现在可用于注入   AppComponent及其所有子组件。

     

AppComponent本身并不需要HeroService。但   它的孩子HeroComponent

专注于构造函数

向构造函数添加参数。

constructor(private _heroService: HeroService) {
  this._heroService.getHeroes().then(heroes => this.heroes = heroes); // or you can use in OnInit
}

N.B:可能无需在constructor

中使用appComponent
  

我们正在使用TypeScript编写,并使用参数名称   类型注释:HeroService。该课程也装饰有   @Component装饰者。

     

当TypeScript编译器评估此类时,它会看到   @Component装饰器并将类元数据添加到生成的内容中   JavaScript代码。在那个元数据中隐藏着那些信息   将heroService参数与HeroService类相关联。

     

Angular注入器如何知道注入一个实例   HeroService创建新HeroComponent

依赖注入的更多细节可以看this link

和层次依赖注入可以看到this link