angular 效劳随记

angular 效劳随记

依靠注入

建立效劳须要用到Injectable,@Injectable() 装潢器把类标记为可供注入的效劳,不过在运用该效劳的 provider 设置好 Angular 的依靠注入器之前,Angular 实际上没法将其注入就任何位置。

provider通知注入器怎样建立该效劳,能够经由过程设置元数据来设置注入器(3种体式格局):

  • 在效劳本身的 @Injectable() 装潢器中。
  • 在 NgModule 的 @NgModule() 装潢器中。
  • 在组件的 @Component() 装潢器中。

@Injectable() 装潢用具有一个名叫 providedIn 的元数据选项,在这里指定把被装潢类的provider放到 root 注入器中,或某个特定 NgModule 的注入器中。

@NgModule() 和 @Component() 装潢器都有效一个 providers 元数据选项,在那里你能够设置 NgModule 级或组件级的注入器。

注入器与效劳实例

在某个注入器局限内,效劳是单例的。运用只要一个根注入器,angular具有多级注入器体系,认为者下级注入器能够建立本身的效劳实例。

每当 Angular 建立一个在 @Component() 中指定了 providers 的组件实例时,它也会为该实例建立一个新的子注入器。 相似的,当在运转时期加载一个新的 NgModule 时(即lazy module),Angular 也能够为它建立一个具有本身的供应商的注入器

借助注入器继承机制,依然能够把全运用级的效劳注入到这些组件中。 组件的注入器是其父组件注入器的子节点,也是其父节点的父节点的子女,以此类推,直到运用的根注入器为止。 Angular 能够注入该继承谱系中任何一个注入器供应的效劳

模块化编程时,service、component、pipe等最好都放在module中,须要引入这些效劳时,经由过程导入module来援用,不要直接import service 和component,这不相符模块化头脑。

多级注入体系

运用程序中有一个与组件树平行的注入器树,关于在什么级别上注入会终究致使:

  • 终究包的大小
  • 效劳的局限
  • 效劳的生命周期

当在效劳本身的@Injectable()装潢器中指定provider时,CLI临盆形式所用的优化东西能够举行摇树优化,它会移除那些没有效过的效劳,摇树优化天生的包更小。

三级provider

  • root级,是AppModule全局的,设置要领已提。
  • NgModule级,两种要领:能够在module的@NgModule 的 provider 元数据中指定;也能够在@injectable() 的providerIn选项中指定某个模块类

假如模块是lazy modole,须要运用@NgModule的provider选项。

  • 组件级为每一个component实例设置本身的注入器

不管关于根级注入器照样模块级注入器,效劳实例的生存期都和运用或模块本身雷同。Angular 能够把这个效劳实例注入就任何须要它的类中(即
app内是单例的)。Angular 只能把响应的效劳注入到该组件实例或其下级组件实例中,而不能把这个效劳实例注入到别的处所(即
组件内并非单例的)。

注入器冒泡

当一个组件请求取得一个依靠时,Angular 先尝试用该组件本身的注入器来满足它。 假如该组件的注入器没有找到对应的供应商,它就把这个请求转给它父组件的注入器来处置惩罚。 假如谁人注入器也没法满足这个请求,它就继承转给它在注入器树中的父注入器。 这个请求继承往上冒泡 —— 直到 Angular 找到一个能处置惩罚此请求的注入器或许超出了组件树中的先人位置为止。 假如超出了组件树中的先人还未找到,Angular 就会抛出一个毛病。

单例效劳

在angular中建立单例效劳有两种体式格局:

  • 在建立效劳时声明该效劳在运用的根上供应
  • 把该效劳包含在AppModule或许某个只会被AppModule导入的模块中

这里第一条很轻易明白。重点第二条:当经由过程@NgMododule()来声明一个serivce时,这个效劳在AppModule内将会是单例的,当一个module中供应了一个service,当另一个
lazy module导入了这个
模块时,angular会为它创一个子注入器,会从新建立service的实例,此service也就多了一个实例。

forRoot()

假如某个模块同时供应了效劳供应商和可声明对象(组件、指令、管道),那末当在某个子注入器中加载它的时刻(比方lazy module),就会天生多个该效劳供应商的实例。 而存在多个实例会致使一些问题,由于这些实例会屏蔽掉根注入器中该效劳供应商的实例,而它的本意多是作为单例对象运用的。 因而,Angular 供应了一种体式格局来把效劳供应商从该模块中分离出来,以便该模块既能够带着 providers 被根模块导入,也能够不带 providers 被子模块导入。

如上文所述,当在运转时期加载一个新的 NgModule 时(即lazy module),Angular 也能够为它建立一个注入器,所以此时导入的其他模块中的service就天生了多个实例,而forRoot能够保证并不建立新的service实例,而是去援用root注入器中的service实例,也就保证了service依然是个单例效劳。

Code

在懒加载模块中导入有service的TestDIModule模块

@NgModule({
  imports: [
    CommonModule,
    BatteryRoutingModule,
    TestDIModule
  ],
  declarations: [BatteryWidgetComponent, BatteryTwoComponent,
    DemoComponent]
})

在TestDIModule模块中

@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [TestDiComponent],
  exports: [TestDiComponent],
  providers: [  ]
})
export class TestDIModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: TestDIModule,
      providers: [
        TestDiService
      ]
    };
  }
 }

在根模块中引入TestDIModule模块

imports: [
    BrowserModule,
    TestDIModule.forRoot(),
  ],

末了在根模块路由中增加这个懒加载模块

const routes: Routes = [
  { path: 'battery', loadChildren: './battery-widget/battery.widget.module#BatteryWidgetModule' },
];

@NgModule({
  exports: [ RouterModule ],
  imports: [ RouterModule.forRoot(routes)
  ],
})

作为测试,能够在TestDIModule中的service中打log看一下

import { Injectable, ModuleWithProviders } from '@angular/core';
import { TestDIModule } from './test-di.module'

@Injectable()
export class TestDiService {

  constructor() {
    console.log('->TestDiService');
  }

  addCoount() {
    this.count++;
    console.log('->count', this.count);
  }

  count = 0;
}
    原文作者:aishuishui2066
    原文地址: https://segmentfault.com/a/1190000019074421
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞