码迷,mamicode.com
首页 > 其他好文 > 详细

Angular2 - Privoder

时间:2019-01-10 16:58:48      阅读:180      评论:0      收藏:0      [点我收藏+]

标签:工作   sar   segment   sele   www.   core   select   方式   参数   

 Angular 2 的核心是依赖注入(DI) ,在深入了解DI的工作原理之前,我们必须先搞清楚 Provider 的概念。

Angular 中的依赖注入

依赖注入(DI)是一种重要的应用设计模式。 Angular 有自己的 DI 框架,在设计应用时通常会用到它,以提升它们的开发效率和模块化程度。

依赖,是当类需要执行其功能时,所需要的服务或对象。 DI 是一种编码模式,其中的类会从外部源中请求获取依赖,而不是自己创建它们。

在 Angular 中,DI 框架会在实例化该类时向其提供这个类所声明的依赖项。本指南介绍了 DI 在 Angular 中的工作原理,以及如何借助它来让你的应用更灵活、高效、健壮,以及可测试、可维护。

@Injectable() 是每个 Angular 服务定义中的基本要素

 

用服务提供商配置注入器

我们创建的类提供了一个服务。@Injectable() 装饰器把它标记为可供注入的服务,不过在你使用该服务的 依赖注入器 提供商配置好 Angular 的之前,Angular 实际上无法将其注入到任何位置。

该注入器负责创建服务实例,并把它们注入到像 HeroListComponent 这样的类中。 你很少需要自己创建 Angular 的注入器。Angular 会在执行应用时为你创建注入器,第一个注入器是根注入器,创建于启动过程中。

提供商会告诉注入器如何创建该服务。 要想让注入器能够创建服务(或提供其它类型的依赖),你必须使用某个提供商配置好注入器。

提供商可以是服务类本身,因此注入器可以使用 new 来创建实例。 你还可以定义多个类,以不同的方式提供同一个服务,并使用不同的提供商来配置不同的注入器。

注入器是可继承的,这意味着如果指定的注入器无法解析某个依赖,它就会请求父注入器来解析它。 组件可以从它自己的注入器来获取服务、从其祖先组件的注入器中获取、从其父 NgModule 的注入器中获取,或从 root 注入器中获取。

你可以用三种方式之一来设置元数据,以便在应用的不同层级使用提供商来配置各个注入器:

  • 在服务本身的 @Injectable() 装饰器中。

  • 在 NgModule 的 @NgModule() 装饰器中。

  • 在组件的 @Component() 装饰器中。

@Injectable() 装饰器具有一个名叫 providedIn 的元数据选项,在那里你可以指定把被装饰类的提供商放到 root 注入器中,或某个特定 NgModule 的注入器中。

@NgModule() 和 @Component() 装饰器都有用一个 providers 元数据选项,在那里你可以配置 NgModule 级或组件级的注入器。

 

依赖注入令牌

当使用提供商配置注入器时,就会把提供商和一个 DI 令牌关联起来。 注入器维护一个内部令牌-提供商的映射表,当请求一个依赖项时就会引用它。令牌就是这个映射表的键。

 

可选依赖

当组件或服务声明某个依赖项时,该类的构造函数会以参数的形式接收那个依赖项。 通过给这个参数加上 @Optional() 注解,你可以告诉 Angular,该依赖是可选的。

当使用 @Optional() 时,你的代码必须能正确处理 null 值。如果你没有在任何地方注册过 logger 提供商,那么注入器就会把 logger 的值设置为 null。

 

多级依赖注入器

Angular 的依赖注入系统是多级的。 实际上,应用程序中有一个与组件树平行的注入器树(译注:平行是指结构完全相同且一一对应)。 你可以在组件树中的任何级别上重新配置注入器。

你可以为注入器树中不同的注入器分别配置提供商。 所有运行中的应用都会共享同一个内部的平台级注入器。 AppModule 上的注入器是全应用级注入器树的根节点,在 NgModule 中,指令级的注入器会遵循组件树的结构。

关于在哪里配置提供商的不同选择将导致一些差异:最终包的大小、服务的范围和服务的生命周期。

当你在服务自身的 @Injectable() 装饰器中指定提供商时(通常在应用的根一级),CLI 生产模式构建时所用的优化工具可以执行摇树优化,它会移除没有用过的那些服务。摇树优化生成的包会更小

 

在 @Injectable 级进行配置

@Injectable() 装饰器会标出每个服务类。服务类的元数据选项 providedIn 会指定一个注入器(通常为 root 来用被装饰的类作为该服务的提供商。 当可注入的类向 root 注入器提供了自己的服务时,任何导入了该类的地方都能使用这个服务。

 

@NgModule 级注入器

你还可以在非根 NgModule 元数据的 providedIn 选项中配置一个模块级的提供商,以便把该服务的范围限定到该模块一级。 这和在 @Injectable() 元数据中指定一个非根模块是基本等效的,但以这种方式提供的服务无法被摇树优化掉。

一般来说,你不必在 providedIn 中指定 AppModule,因为应用中的 root 注入器就是 AppModule 注入器。 不过,如果你在 AppModule 的 @NgModule() 元数据中配置了全应用级的提供商,它就会覆盖通过 @Injectable() 配置的那一个。 你可以用这种方式来为那些供多个应用使用的服务指定非默认的提供商。

 

@Component 级注入器

NgModule 中每个组件都有它自己的注入器。 通过使用 @Component 元数据在组件级配置某个提供商,你可以把这个提供商的范围限定到该组件及其子组件。

 

元素注入器

注入器本质上并不属于组件,而是 DOM 中该组件实例所附着到的元素。另一个 DOM 元素上的其它组件实例则会使用另一个注入器。

 

技术分享图片

在 Angular 2 中我们使用 Provider 来描述与 Token 关联的依赖对象的创建方式。Angular 2 中依赖对象的创建方式有四种,它们分别是:

  • useClass

@Injectable()
export class ApiService {
   constructor(
      public http: Http, 
      public loadingCtrl: LoadingController) {
   }
   ...
}

@NgModule({
  ...
  providers: [
       { provide: ApiService, useClass: ApiService } // 可使用简洁的语法,即直接使用ApiService
  ]
})
export class CoreModule { }
  • useValue

{ provide: API_URL, useValue: http://api.com/ }
  • useExisting

{ provide: ApiServiceAlias, useExisting: ApiService }
  • useFactory

export function configFactory(config: AppConfig) {
  return () => config.load();
}

@NgModule({
  ...
  providers: [
       { provide: APP_INITIALIZER, useFactory: configFactory, 
        deps: [AppConfig], multi: true }
  ]
})
export class CoreModule { }

使用 Provider

1.创建 Token

Token 的作用是用来标识依赖对象,Token值可能是 Type、InjectionToken、OpaqueToken 类的实例或字符串。通常不推荐使用字符串,因为如果使用字符串存在命名冲突的可能性比较高。在 Angular 4.x 以前的版本我们一般使用 OpaqueToken 来创建 Token,而在 Angular 4.x 以上的版本版本,推荐使用 InjectionToken 来创建 Token 。

2.根据实际需求选择依赖对象的创建方式,如 useClass 、useValue、useExisting、useFactory

3.在 NgModule 或 Component 中注册 providers

4.使用构造注入的方式,注入与 Token 关联的依赖对象

/**
* 封装Http服务,如在每个Http的请求头中添加token,类似于Ng1.x中的拦截器
*/
@Injectable() 
export class ApiService {
   constructor(
   // 注入Angular 2 中的Http服务,与Ng1.x的区别:
   // 在Ng1.x中调用Http服务后,返回Promise对象
   // 在Ng2.x中调用Http服务后,返回Observable对象
      public http: Http) { 
   }
   ...
}

/**
* AppModule
*/
@NgModule({
  ...
  providers: [
       { provide: ApiService, useClass: ApiService } // 可使用简洁的语法,即直接使用ApiService
  ]
})
export class AppModule { }

/**
* 系统首页
*/
@Component({
  selector: page-home,
  templateUrl: home.html
})
export class HomePage {
  constructor(
    public apiService: ApiService // 使用构造注入的方式,注入ApiService的实例对象
  ) { }
  
  ngOnInit(): void {
    this.apiService.get(HOME_URL) // 获取首页相关的数据
    .map(res => res.json()) // 返回的res对象是Response类型的实例
    .subscribe(result => {
      ...
    })
  }
}

 

Angular2 - Privoder

标签:工作   sar   segment   sele   www.   core   select   方式   参数   

原文地址:https://www.cnblogs.com/allenj/p/10250916.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!