angularjs培训之service

原文地址:http://angular-tips.com/blog/2013/08/understanding-service-types/

Angular中有几种不同类型的services。每一种都有自己的独特用法。

需要记住的非常重要的一点是service总是一个单体,无论是哪种类型的service,这是个很被期望的行为。

注释:单体是一种设计模式,它限制了每一个类仅能够实例化为一个对象。无论我们在什么地方注入我们的service,将永远使用同一个实例。

Provider

Provider是几乎所有service的根源(除了contant),但也是最复杂并且可以配置。我们先看下一个基本用法:

app.provider(‘foo‘, function() {  
            return {    
                $get: function() {      
                    var thisIsPrivate = "Private";      
                    function getPrivate() {        
                        return thisIsPrivate;      
                    }      
                    return {        
                        variable: "This is public",        
                        getPrivate: getPrivate      
                    };    
                    }  
              };});

一个provider,最简单的形式是返回一个$get方法,p rovider注册的即是我们在其他组件中可以注入的部分。如果我们有一个controller,想把foo作为一个provider注入,我们注入的部分就是$get方法部分。

使用factory不是更简单吗为什么我们要使用provider,因为我们可以在config()中配置provider,可以这么使用:

    app.provider(‘foo‘, function() {  
        var thisIsPrivate = "Private";  
        return {    
        setPrivate: function(newVal) {      
                        thisIsPrivate = newVal;    
                        },    
         $get: function() {      
                 function getPrivate() {        
                         return thisIsPrivate;      
                 }      
                 return {        
                     variable: "This is public",        
                     getPrivate: getPrivate      
                     };    
               }  
       };});
                     
     app.config(function(fooProvider) {  
         fooProvider.setPrivate(‘New value from config‘);
     });

在这里我们把 thisIsPrivate 移到了$get方法的外部,为的是在config中可以配置。为神马我们需要这么做呢?将setter方法增加到$get是不是更加简单?这是因为不同的目的。

想象一下你想创建一个通用库用来管理models和REST请求。如果你将目标URLs硬编码,这样的库不再通用,所以比较好的想法是将URLs可以配置,我们可以创建一个provider使得URLs在config方法中可以配置。

需要注意的是我们将nameProvider注入到config而不是name,如果是注入到$get中可以使用name(后半句是个人理解,不知道是否合理,留作一个问题,后续验证下)。

看到这里,我们意识到,我们已经在应用中配置过一些服务,像$routeProvider和$locationProvider配置routes和html5mode。

Providers有两种注入方式,provider constructor 和$get方法。provider constructor仅能注入其他providers和constants(在配置方面有相同的限制)。在$get方法中可以注入除了其他的provider的服务(但是可以注入其他provider的$get方法)

注意:注入一个provider使用:name+‘Provider‘, 如果注入到它的$get方法可以使用name

Factory

Provider非常棒,但是相当灵活也比较复杂,我们只是想使用它的$get方法?我的意思是,根本不用配置,这样的话我们嗨可以使用factory,让我们先看一个例子,

app.factory(‘foo‘, function() {
  var thisIsPrivate = "Private";
  function getPrivate() {
    return thisIsPrivate;
  }
  return {
    variable: "This is public",
    getPrivate: getPrivate
  };
});
// or..
app.factory(‘bar‘, function(a) {
  return a * 2;
});

正如你看到的,把provider的$get方法移到了一个factory中,和第一的provider相比简单多了。事实上,factory内部只用了一个$get方法。

正如前面介绍的,所有的service都是单例的,如果我们在一个地方修改foo.variable的值,其他地方的值也将会修改。

我们可以注入所有的服务(除了providers)到factory。可以注入(如上面的foo,bar)到任何的地方除了provider constructor 和 config方法。(具体的例子可以参考原文)

Value

Factory很好用,但是如果我们仅存储一个简单的值呢?我的意思是,没有注入,只是一个简单的值或对象,angular提供一个叫做value的service。

app.value(‘foo‘, ‘A simple value‘);

value的内部实现只是一个fa ctory。jiran它是一个factory那么仍然要遵循它的注入方法。AKA不能被注入到provider constructor 和config方法

Service

到现在我们提到了复杂的provider,比较简单多factory和value 服务,service服务时什么样子的?我们先看下这个例子:

app.service(‘foo‘, function() {
  var thisIsPrivate = "Private";
  this.variable = "This is public";
  this.getPrivate = function() {
    return thisIsPrivate;
  };
});

service服务的工作方式可以factory很相似,区别也是很简单:factory接受一个方法,这个方法在创建时调用,service接受一个构造方法(内部使用Object.create创建而不是使用new),

事实上,下面的代码将实现相同的功能:

app.factory(‘foo2‘, function() {
  return new Foobar();
});
function Foobar() {
  var thisIsPrivate = "Private";
  this.variable = "This is public";
  this.getPrivate = function() {
    return thisIsPrivate;
  };
}

Foobar是一个构造方法,在angular处理过程中被实例化然后返回。Foobar会被初始化一次,接下来我们使用factory会返回同样的实例。

有了构造方法,可以使用service服务了,如下:

app.service(‘foo3‘, Foobar);

Constant

constant是provider的子类型,和value 服务的用法比较相似:

app.constant(‘fooConfig‘, {
  config1: true,
  config2: "Default config2"
});

和value有什么区别呢?constant可以被注入到任何地方,包括provider constructor 和config 方法。这就是为什么使用constant 服务为directive设置默认配置,因为可以在config方法中修改这些配置。

你可能正在考虑为什么命名为constant,这只是一个设计决定,并不知道它背后的原因。

Decorator

那么现在已经决定要使用前面的 foo service,但是其中还是缺少一个你想要的greet函数。你可以修改factory吗?答案是不行!但是你可以装饰它:

app.config(function($provide){
    $provide.decorator(‘foo‘,function($delegate){
        $delegate.greet = function(){
            return "Hello, I am a new function of ‘foo‘";
        }
    });});

$provide是Angular用来在内部创建我们的service的东西。如果我们想要使用它的话可以手动来使用它或者仅仅使用在我们的模块中提供的函数(我们需要使用$provide来进行装饰)。$provide有一个函数,decorator,它让我们可以装饰我们的service。它接收我们想要装饰的service的名字并且在回调函数中接收一个$delegate来代表我们实际上的service实例。

在这里我们可以做一切我们想要的事情来装饰我们的service。在上面的例子中,我们为我们原来的service添加了一个greet函数。接着我们返回了修改后的service。

经过修改以后,现在我们的factory中已经有了一个叫做greet的函数。

装饰一个service的能力是非常实用的,尤其是当我们想要使用第三方的service时,此时我们不需要将代码复制到我们的项目中,而只需要进行一些修改即可。

注意:constant service不能被装饰。

创建一个实例

我们的services都是单体但是我们可以创建一个单体factory来创建新的实例。在你深入之前,记住Angular中的服务都是单体并且我们不想改变这一点。但是,在极少数的情况下你需要生成一个新的实例,你可以像下面这样做:

//我们的类   
function Person(json){
    angular.extend(this,json);
  }
  Person.prototype = {
    update: function(){
        //更新内容   
        this.name = "Dave";
        this.country = "Canada";
    }};   Person.getById = function(id){
    //由id来获取一个Person的信息   
    return new Person({
        name: "Jesus",
        country: "Spain"
        });
  };
  //我们的factory   
app.factory(‘personService‘,function(){
    return {
        getById: Person.getById    
        };
 });

在这里我们创建了一个Person对象,它接收一些json数据来初始化对象。然后我们在我们的原型(原型中的函数可以被Person的实例所用)中创建了一个函数,并且在Person上直接创建了一个函数(就像是类函数一样)。

因此现在我们拥有了一个类函数,它将基于我们提供的id来创建一个新的Person对象,并且每一个对象都可以自我更新。现在我们仅仅需要创建一个能够使用它的service。

当每次我们调用personService.getById时,我们都在创建一个新的Person对象,因此你可以在不同的控制器中使用这个service,即便当factory是一个单体,它也能生成新的对象。

总结

Service是Angular中最酷的特性之一。我们可以使用很多方法来创造它们,我们仅仅需要找到符合我们需求的方法然后实现它。

时间: 2024-11-06 17:46:58

angularjs培训之service的相关文章

angularjs培训之重新理解双向绑定和事件详解

双向绑定是angularjs亮点之一,在前面的<angularjs培训之helloworld>篇中大概介绍了下双向绑定,现在我们"旧事重提",先看下下面的代码片段: view中:  <input type='button' ng-click="set()" value="set Value">  <input type="text" ng-model='userName2'> control

angularjs 中 Factory,Service,Provider 之间的区别

本片文章是使用了 angularjs 中使用 service 在controller 之间 share 对象和数据 的code(http://jsfiddle.net/kn46u0uj/1/) 来进行演示 Factory,Service,Provider 之间的区别 1. Factory factory('dataService',function(){ return { golbal_sitename:"this is the shared value", sayHello:func

angularjs 中使用 service 在controller 之间 share 对象和数据

在做angularjs 的UI 时,我们经常会遇到一个页面之间有几个controller,在controller 之间share 公共的一些数据和方法就变得比较困难,目前推荐的做法是使用创建一个service, 在service 中存储公共的数据,然后把service 注入到controller中来达到share 数据的目的. 下面是最简单的一个sample 列子 angularjs 模板页面, 有userContoller 和 customerController,我们将在这两个control

angularjs培训之Scope嵌套

每部分的angularjs应用都有一个父scope(但是ng-app对应的是$rootScope,这个scope是终极scope),除了isolate scope,所有的scope都是通过原型继承来创建,也就是说可以访问它的父的scope.如果你对OOP比较熟悉,这种行为你看起来就比较熟悉了. 每次html渲染属性和方法是,会从当前的scope中寻找,如果没有找到,就从他的父scope中寻找,直到检索到$rootScope中,如果还没有找到就会报错. 下面看个例子: <DIV ng-contro

理解AngularJS中的Service类型

Angular中有几种不同类型的services.每一种都有自己的独特用法. 需要记住的非常重要的一点是service总是一个单体,无论是哪种类型的service. 注释:单体是一种设计模式,它限制了每一个类仅能够实例化为一个对象.无论我们在什么地方注入我们的service,将永远使用同一个实例. Constant 例子: app.constant('fooConfig',{ config1: true, config2: "Default config2" }); Constant是

angularJS培训之helloworld篇

学习一门新的语言我们总是来句'hello,world!',来,我们看下angularJS的helloworld版本是怎么实现的. 1.首先我们下载angularJS库,你可以从官网angularjs.org或者github下载,也可以从github上的         angular-seed 项目中找到对应库文件,也可以通过Google的CDN网络加载文件.通过script标签引入到文件中 2.开发工具 js开发的神器首推webstorm莫属,超强的重构能力,karma,grunt的支持,js

AngularJS中使用service,并同步数据

service是单例对象,在应用中不同代码块之间共享数据. 对一些公用的方法封装到service中,然后通过依赖注入在Controller中调用,示例代码: 1.创建一个模块: var module = angular.module( "my.new.module", [] ); 2.创建一个service服务: module.service( 'Book', [ '$rootScope', function( $rootScope ) { var service = { books:

angularjs培训之filter

在angularjs中,filter提供了格式化数据或者过滤数据的功能: 1.请看下面简单的例子 <div ng-controller="phoneListExtendController"> I have {{friends.length}} friends. They are: <input type="search" ng-model="q" placeholder="filter friends..."

[AngularJS] Using $parse Service

$parse is useful when you want to parse an expression and the context is not defined yet. For example, I have a table component which allows user to pass in all the row items and define action for each row. <ttmd-table items="vm.invoices" hea