• 在angular2服务中注入服务


    http://kittencup.com/javascript/2015/11/11/%E5%9C%A8angular2%E6%9C%8D%E5%8A%A1%E4%B8%AD%E6%B3%A8%E5%85%A5%E6%9C%8D%E5%8A%A1.html

    如果你关注我们的文章 Angular2中的依赖注入,你知道DI系统在Angular中是如果运作的,它利用在我们代码上通过注解添加metadata来获取所有关于依赖的信息来解决我们的依赖关系

    Angular 2 应用基本上可以用任何语言编写。只要它以某种方式编译成JavaScript,当我们使用Typescript编写我们应用时,我们使用decorator来给我们代码添加metadata,有时,我们甚至忽略一些decorator,单纯依靠类型注释。然而,事实证明,当涉及到DI,我们可能注入依赖到服务时遇到意外的行为。

    本文讨论了这个意外的问题,为什么它存在,以及如何解决。

    注入服务依赖

    比方说我们有一个简单的Angular 2 组件有一个DataService依赖,它可能是这个样子:

    @Component({
      selector: 'my-app'
    })
    @View({
      directives: [NgFor],
      template: `
        <ul>
          <li *ng-for="#item in items"></li>
        </ul>
      `
    })
    class AppComponent {
      items:Array<any>;
      constructor(dataService: DataService) {
        this.items = dataService.getItems();
      }
    }
    

    另一方面 DataService 是一个简单的类(因为它在Angualr2是一个服务),它提供了一个方法返回一些items

    class DataService {
      items:Array<any>;
    
      constructor() {
        this.items = [
          { name: 'Christoph Burgdorf' },
          { name: 'Pascal Precht' },
          { name: 'thoughtram' }
        ];
      }
    
      getItems() {
        return this.items;
      }
    }
    

    当然,为了能使用DataService类型,我们必须为injector添加这个provider,当引导我们的应用时可以这样做,通过传递一个provider给boostrap();

    bootstrap(AppComponent, [DataService]);
    

    到现在为止没有什么新的内容,如果这对你来说是新内容,你可能需要先阅读我们的Angular2中的依赖注入文章。

    那么问题在那里呢? 这个问题发生在当我们试图注入一个依赖进我们的服务,比如,我们可以使用Http在我们的DataService里从远程服务器获取数据,让我们快速实现这个。首先,我们需要为injector提供一个provider,让DataService知道有关http。

    import {HTTP_PROVIDERS} from 'angular2/http';
    
    ...
    
    bootstrap(AppComponent, [HTTP_PROVIDERS, DataService]);
    

    Angular http模块 暴露了 HTTP_PROVIDERS,它包含了所有的我们需要用到的http操作的provider,接下来,我们需要在我们的服务中注入这个实例

    import {Http} from 'angular2/http';
    
    class DataService {
      items:Array<any>;
    
      constructor(http:Http) {
        ...
      }
      ...
    }
    

    轰. 这个东西会爆炸。当我们在浏览器中运行这段代码,我们会得到以下错误:

    Cannot resolve all parameters for DataService(?). Make sure they all have valid type or annotations.
    

    这错误基本上的意思是,它不能解决DataService的Http依赖,因为Anuglar不知道该类型,因此 没有provider可以用来解决该依赖,恩。。等等,我们没有将变量类型提供给了constructor吗?

    不,我们提供了,不幸的是,这是不够的,但是 在我们的AppComponent我们注入的DataService显然是在正常工作,那在这里有什么问题?

    在我们的Annotation和Decorator之间的区别文章,我们获悉,decorator只是简单的为我们的代码添加metadata,我们来看下编译后的AppComponent的decorator

    function AppComponent(myService) {
      ...
    }
    
    AppComponent = __decorate([
      Component({...}),
      View({...}), 
      __metadata('design:paramtypes', [DataService])
    ], AppComponent);
    

    我们可以清楚地看到,AppComponent类会被__decorate函数给包装,里面包装了Component,View 和 paramtypes的metadata,

    paramtypes 元素是一个告诉angular DI用来弄清楚,它必须返回一个什么类型的实例

    这看起来很不错。让我们来看看被编译后的DataService,看看在那里发生了什么事情(也简化了)。

    DataService = (function () {
      function DataService(http) {
        ...
      }
      return DataService;
    })();
    

    哎呀。显然,在这里没有任何metadata。这是为什么?

    当设置了emitDecoratorMetadata选项,TypeScript会生成metadata,然而,这并不意味着它会盲目的为我们代码的每个类或方法生成metadata,TypeScript只会对那些被decorator附加的类,方法,属性或者构造函数参数来生成相应的metadata ,否则,会产生大量的未使用的metadata代码,这不仅影响文件的大小,也对我们的应用程序运行产生影响。

    这就是为什么AppComponent会生成metadata,而DataService 不生成,我们的AppComponent有一个decorator

    强制生成metadata

    那么我们如果才能强制TypeScript为我们生成metadata呢,我们可以做的一件事,就是用框架提供的Di decorator,正如我们在DI的其他文章中了解到,@Inject decorator用来要求某种类型的依赖

    我们可以改变我们的DataService的成这样的:

    import {Inject} from 'angular2/core';
    import {Http} from 'angular2/http';
    
    class DataService {
      items:Array<any>;
    
      constructor(@Inject(Http) http:Http) {
        ...
      }
      ...
    }
    

    问题解决。事实上,如果查看经过编译后的代码时会发现已生成需要的metadata

    function DataService(http) {
    }
    DataService = __decorate([
      __param(0, angular2_1.Inject(Http)), 
      __metadata('design:paramtypes', [Http])
    ], DataService);
    

    我们基本上可以在我们代码上做任何decorator,只要在class,或者构造函数参数上附加任何decorator,换一种说法,我们可以把 @Inject 移除,然后在这个类上使用别的decorator,因为这将导致TypeScript为构造函数参数生成metadata

    当然。在一个类上使用一个decorator,来解决所有的问题,听起来不是很合适。幸运的是,我们可以使用Angular自带的另一个decorator。@Injectable 是一个用于Dart的metadata创建,在TypeScript,它没有任何特殊含义,然而,事实证明是非常适合我们的用例.

    我们所要做的就是导入它,把它放在我们的DataService

    import {Injectable} from 'angular2/core';
    import {Http} from 'angular2/http';
    
    @Injectable()
    class DataService {
      items:Array<any>;
    
      constructor(http:Http) {
        ...
      }
      ...
    }
    

    同样,它只是强制TypeScript发射需要的matadata,这个decorator在这里并没有什么特殊含义,这似乎是我们目前解决所示问题的最佳选择

    互相学习 互相提高
  • 相关阅读:
    jquery的常用api和两个特性
    react脚手架和深入理解jsx语法
    前端常见的性能优化
    前后端交互模型(一个面试题引发的思考总结)
    jquery源码部分分析
    bootstrap快速上手
    vue总结
    MySQL连接查询驱动表被驱动表以及性能优化
    一分钟掌握MySQL的InnoDB引擎B+树索引
    一分钟明白MySQL聚簇索引和非聚簇索引
  • 原文地址:https://www.cnblogs.com/huxiangxuexie/p/5070785.html
Copyright © 2020-2023  润新知