AngularJS权威指南-服务

3031次阅读
没有评论

共计 4632 个字符,预计需要花费 12 分钟才能阅读完成。

一、为什么要使用服务

视图同$scope绑定在一起,而控制器管理数据。出于内存占用和性能的考虑,控制器只会在需要时被实例化,并且不再需要就会被销毁。这意味着每次切换路由或者重新加载视图时,当前的控制器会被angularJS清理掉。

服务提供了一种能在应用的整个生命周期内保持数据的方法,它能够在控制器之间进行通信,并且能保证数据的一致性。服务是一个单例对象,在每个应用中只会被实例化一次(被$injector实例化),并且是延迟加载的(需要时才会创建),服务提供了把与特定功能相关联的方法集中在一起的接口。

二、注册一个服务

创建服务的方法有共有5种:

  1. factory(),这是最常见也是最灵活的方式。
    factory()函数接受两个参数,第一个name(这是一个字符串,表示服务的名字),第二个function(这个函数在angularJS创建服务实例时会被调用)

    angular.module('myApp.services',[]).factory('scervicesName',[function(){
           return {
               //例如返回的对象有如下方法。这个返回的对象就是服务。
               //有时这个返回也可以是一个函数,简单类型等任意类型的数据。
               nameVlue:'hello word',
               gerFn:function(){},
               setFn:function(){},
               ...
           }
    }])

    服务的工厂函数用来生成一个单例对象或函数。这个对象或者函数就是服务,它会存在于应用的整个生命周期内。

  2. service()可以注册一个支持构造函数的服务
    sercive()方法接受两个参数,第一个name(这是一个字符串,表示服务的名字),第二个constructor(这个一个构造函数,在angularJS创建服务实例时会被调用)

    angular.service('peopleName',['$http',function($http){//$http这是一个内置的服务,
          this.getname = function(){
               return $http({method:'GET',url:'/user'})
          }
    }])
  3. porvider()
    所有的服务工厂都是由$pervider服务创建的,$porvider服务负责在运行时初始化这些提供者。
    提供者是一个具有$get()方法的对象,$injector通过调用$get方法创建服务实例。$provider提供了数个不同的API用于创建服务,每个方法都有不同的用途。
    其他4个方法都是基于porvider方法创建的。porvider()方法负责在$porviderCache中注册服务。比如下面另个方法作用完全一样。

    angular.module('myApp.services',[])
    .factory('scervicesName',[function(){
           return {
               nameVlue:'hello word'
           }
    }])
    .provider('scervicesName',{ 
        $get:function(){
             return {
                 nameVlue:'hello word'
             }
        }
    })

    如果需要对porvider()方法的服务进行额外的扩展配置。例如:

    angular.module('myApp.services',[])
    .provider('gitHubService',['$http',function($http){
         var githubUrl = 'www.github.com'
         setUrl:function(url){
             if(url){githubUrl =url }
         },
         method:'JSONP',
         $get:function(){
             self = this,
             return $http({method:self.method,url:githubUrl+'/user'})
         }
    }])

    然后在需要调用的地方。用config()方法注入特殊的参数。

    angular.module('myApp.services',[])
    .config(function(gitHubServicePorvider){
         gitHubServicePorvider.setUrl('www.baidu.com');
    })

    porvider()方法为服务注册提供者,可以接受两个参数;第一个name(这是一个字符串,表示服务的名字),第二个aPorvider(对象/函数/数组);
    当aPorvider是函数,那么它会通过依赖注入被调用,并且负责通过$get方法返回一个对象。
    当aPorvider是数组,那么它会被当做一个带有行内依赖注入声明的函数来处理,数组的最后一个元素必须是对象,可以返回一个带有$get方法的对象。
    当aPorvider是对象,那么它应该带有$get方法。

    angular.module('myapp',[])
    .provider('UserService',{
    
         name:'zzr',
         setName:function(new){
             if(new){this.name=new}
         },
         $get:function(){
             return {
                'name':'ari',
                getF:function(){
                    return this.name || "unknown"
                }
             }
         }
    })

    如果你要实例化服务(一般的angularJS会自动处理服务的实例化,很少自己动手),可以使用$injector.

    var injector = angular.injector(['myapp']);
        injector.invoke(['UserService',function(UserService){
             //...
       }])
  4. constant(),可以将一个已经存在的变量值注册为服务,并将其注入到应用的其他部分当中。可用于指令或者控制器之间传递的常量!
    constant()函数接受两个参数,第一个name(这是一个字符串,表示服务的名字),第二个value(常量)需要注册的常量的值或者对象。该方法返回一个注册后的服务实例。例如

    angular.module('myapp').constant("key","123123123");
    angular.module('myapp').controller('myCtrl',function($scope,key){
           $scope.key = key;
    })
  5. value(),如果$get方法返回的是一个常量,那么可以直接使用value()函数方便的注册服务。
    value()函数接受两个参数,第一个name(这是一个字符串,表示服务的名字),第二个value(常量),将这个值将作为可以注入的实例返回。

    angular.module('myapp').value("key","123123123");

    value()和constant()的区别,常量可以注入到配置的函数中,而值不行。通常value()来注册服务对象或函数,用constant()来配置数据

    angular.module('myapp',[])
    .constant("key1","123123131")
    .config(function(key1){
        //这里key1将会被赋值为123123131
    })
    .value("key","lalala")
    .config(function(key){
        //这里将抛出一个错误,因为这里无法访问key。
    })
  6. decorator()(翻译为装饰器),$provide服务提供了在服务实例创建时对其进行拦截的功能,可以对服务进行扩展,或者用另外的内容完全代替它。ng的很多功能都是借助$provide.decorator()建立的。对服务进行装饰的场景有很多,比如对服务进行扩展,将外部数据缓存进localStorage的功能等等。
    decorator()函数接受两个参数,第一个name(这是一个字符串,表示服务的名字),第二个function,这个函数由injector.invoke调用。可以将服务注入这个函数中,
    $delegate是可以进行装饰的最原始的服务,为了装饰其他服务,需要将其注入进装饰器。
    例如:下面代码展示了如何给Service添加装饰器,从而为每个请求都加上一个时间戳。

    angular.module('myapp',[])
    .config(function($provide){
       $provide.decorator('Service',function($delegate,$log){
            return {
               events:function(path){
                   var startedAt = new Date();
                   var events = $delegate.events(path);
                   events.finally(function(){
                       $log.info('Fetching took ' + (new Date() - startedAt) + 'ms')
                   })
                   return events;
               }
            }
       })
    })

三、使用服务

可以在控制器,指令,过滤器,或另外的一个服务中通过依赖注入的方式使用服务。将服务的名字当做参数传递给控制器函数,可以将服务注入到控制器中,当服务成为了某个控制器的依赖,就可以在控制器中调用任何定义在这个服务对象的方法。

angular.module('myapp',['myapp.services'])
.controller('serviceCtrl',function('$scope','githubService'){
     //依赖注入的规则是内置的服务在前,之后在写自定义的服务
     //这里可以使用githubService上的任何方法。
     //使用起来就是这么简单
})

如果我们的应用中一个用来设置GITHUB用户名的设置页面,我们希望在应用中所有的控制器之间共享用户名。为了在控制器之间共享数据,需要在服务中添加一个用来储存用户名的方法。记住,服务在应用的生命周期内是单利模式的,因此可以将用户名安全地储存在其中。

angular.module('myapp.services',[])
.factory('githubService',function($http){
    var gitUrl = 'http://github.com',getName;
    var runUserRequest = function(path){
        return $http({
            method:"JSONP",
            url:gitUrl +'/users/' + getName +'/'+path+'?callback=JSON_callback'
        });
    }
    return {
        events:function(){
             return runUserRequest('events');
        },
        setUsername : function(username){
           getName = username;
        }
    }
})
//-----------------------------------------
// githubService可以注入到任何一个控制器中,并可以在控制中调用events方法;
angular.module('myapp',['myapp.services'])
.controller('ServiceCtrl',function($scope,githubService){
   $scope.setUsername  = githubService.setUsername;
})

正文完
 0
Chou Neil
版权声明:本站原创文章,由 Chou Neil 于2016-05-03发表,共计4632字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。