Angular开发者指南(五)服务

比特追光者
• 阅读 2375

服务
AngularJS服务是使用依赖注入(DI)连接在一起的可替代对象。 可以使用服务在整个应用程式中整理和分享程式码。
AngularJS服务有:

  • 延迟初始化 - AngularJS只在应用程序组件依赖它时实例化服务。

  • 单例 - 依赖于服务的每个组件获取对服务工厂生成的单个实例的引用。

AngularJS提供了几个有用的服务(如$http),但对于大多数应用程序,你也想创建自己的。像其他核心的AngularJS标识符一样,内置服务总是以$开头(例如$http)。
使用服务
要使用AngularJS服务,请将其添加为依赖于依赖于服务的组件(控制器,服务,过滤器或指令)的依赖项。 AngularJS的依赖注入子系统负责其余的。

index.html

<div id="simple" ng-controller="MyController" ng-app="myServiceModule">
  <p>让我们尝试这个简单的通知服务,注入到控制器</p>
  <input ng-init="message='test'" ng-model="message" >
  <button ng-click="callNotify(message);">NOTIFY</button>
  <p>(必须点击3次才能看到提醒)</p>
</div>

script.js

angular.
module('myServiceModule', []).
 controller('MyController', ['$scope', 'notify', function($scope, notify) {
   $scope.callNotify = function(msg) {
     notify(msg);
   };
 }]).
factory('notify', ['$window', function(win) {
   var msgs = [];
   return function(msg) {
     msgs.push(msg);
     if (msgs.length === 3) {
       win.alert(msgs.join('\n'));
       msgs = [];
     }
   };
 }]);

protractor.js

it('should test service', function() {
  expect(element(by.id('simple')).element(by.model('message')).getAttribute('value'))
      .toEqual('test');
});

需要点击三次NOTIFY按钮才会出现弹出框内容
创建服务
应用程序开发人员可以使用AngularJS模块注册服务的名称和服务工厂函数来自由定义自己的服务。
服务工厂函数生成表示对应用程序其余部分的服务的单个对象或函数。 服务返回的对象或函数被注入到指定对服务的依赖性的任何组件(控制器,服务,过滤器或指令)中。
注册服务
服务通过Module API注册到模块。 通常您使用Module factory API注册服务:

var myModule = angular.module('myModule', []);
myModule.factory('serviceId', function() {
  var shinyNewServiceInstance;
  // 构造shinyNewServiceInstance的工厂函数体
  return shinyNewServiceInstance;
});

此时不是注册服务实例,而是一个在调用时将创建此实例的工厂函数。
依赖
服务可以有自己的依赖。 就像在控制器中声明依赖项一样,可以通过在服务的工厂函数签名中指定依赖性来声明它们。
下面的示例模块有两个服务,每个具有各种依赖关系:

var batchModule = angular.module('batchModule', []);

/**
 *`batchLog'服务允许消息在内存中排队,并且每50秒刷新到console.log 
 */
batchModule.factory('batchLog', ['$interval', '$log', function($interval, $log) {
  var messageQueue = [];

  function log() {
    if (messageQueue.length) {
      $log.log('batchLog messages: ', messageQueue);
      messageQueue = [];
    }
  }

  // 开始定期检查
  $interval(log, 50000);

  return function(message) {
    messageQueue.push(message);
  }
}]);

/**
 *`routeTemplateMonitor`监视每个`$ route`更改,并通过`batchLog`服务记录当前模板
 */
batchModule.factory('routeTemplateMonitor', ['$route', 'batchLog', '$rootScope',
  function($route, batchLog, $rootScope) {
    return {
      startMonitoring: function() {
        $rootScope.$on('$routeChangeSuccess', function() {
          batchLog($route.current ? $route.current.template : null);
        });
      }
    };
  }]);

在示例中,需要注意的是:

  • batchLog服务取决于内置的$interval和$log服务。

  • routeTemplateMonitor服务取决于内置的$route服务和$rootscope和我们的自定义batchLog服务。

  • 两个服务都使用数组符号来声明它们的依赖关系。

  • 数组中标识符的顺序与工厂函数中参数名称的顺序相同。

还可以通过模块的配置函数中的$provide服务注册服务:

angular.module('myModule', []).config(['$provide', function($provide) {
  $provide.factory('serviceId', function() {
    var shinyNewServiceInstance;
    // 构造shinyNewServiceInstance的工厂函数体
    return shinyNewServiceInstance;
  });
}]);

这种技术通常用于单元测试中来模拟服务的依赖。
单元测试
以下是来自上面的创建服务示例的通知服务的单元测试。 单元测试示例使用Jasmine spy(mock),而不是真正的浏览器alert。

var mock, notify;
beforeEach(module('myServiceModule'));
beforeEach(function() {
  mock = {alert: jasmine.createSpy()};
  module(function($provide) {
    $provide.value('$window', mock);
  });
  inject(function($injector) {
    notify = $injector.get('notify');
  });
});
it('should not alert first two notifications', function() {
  notify('one');
  notify('two');

  expect(mock.alert).not.toHaveBeenCalled();
});
it('should alert all after third notification', function() {
  notify('one');
  notify('two');
  notify('three');
  expect(mock.alert).toHaveBeenCalledWith("one\ntwo\nthree");
});
it('should clear messages after alert', function() {
  notify('one');
  notify('two');
  notify('third');
  notify('more');
  notify('two');
  notify('third');
  expect(mock.alert.calls.count()).toEqual(2);  expect(mock.alert.calls.mostRecent().args).
  toEqual(["more\ntwo\nthird"]);
});
点赞
收藏
评论区
推荐文章
Stella981 Stella981
3年前
React 服务端渲染完美的解决方案
最近在开发一个服务端渲染工具,通过一篇小文大致介绍下服务端渲染,和服务端渲染的方式方法。在此文后面有两中服务端渲染方式的构思,根据你对服务端渲染的利弊权衡,你会选择哪一种服务端渲染方式呢?什么是服务器端渲染使用React构建客户端应用程序,默认情况下,可以在浏览器中输出React组件,进行生成DOM和操作DOM。Re
Stella981 Stella981
3年前
AngularJS 常用指令
AngularJS指令AngularJS有一套完整的、可扩展的、用来帮助web应用开发的指令集,它使得HTML可以转变成“特定领域语言(DSL)”,是用来扩展浏览器能力的技术之一,在DOM编译期间,和HTML关联着的指令会被检测到,并且被执行,这使得指令可以为DOM指定行为,或者改变它。AngularJS指令带有前
Wesley13 Wesley13
3年前
ECS主动运维2.0,体验升级,事半功倍
_摘要:_ 阿里云致力于提供更好用的运维体验,让您使用ECS的过程更透明、高效,并实现更加标准化、自动化的运维方式。基于主动运维2.0,您使用ECS云服务器的体验更加流畅,而且利用系统事件,不再依赖于工单联系客服,可以通过自助处理的方式响应主动运维实例重启,减少对系统可靠性和业务连续性的影响。   云服务器ECS(ElasticCompute
Stella981 Stella981
3年前
AngularJs初探
  最近着手开发一个后台系统,前端采用的是AngularJs来与后台交互,对于我们这群jquery疯狂的铁粉,遇到了不少转不过弯的问题,为了更高效的开发应用,在私下的时间收集和改造了一下AngularJS的$http服务,特此分享。$http的post.请求默认的contentTypeapplication/json.提交
Stella981 Stella981
3年前
Hystrix——让你的服务更稳一点
摘要:1、为什么要用Hystrix在分布式服务环境下,服务之间的调用关系变得错综复杂,你是否担心依赖的服务延迟导致自己的服务也被拖跨呢?是否在苦苦思考如何优雅的对依赖服务进行异步调用呢?是否希望当流量高峰时自动进行...
Easter79 Easter79
3年前
SpringCloud之Hystrix服务降级(七)
Hystrix设计原则1.防止单个服务的故障,耗尽整个系统服务的容器(比如tomcat)的线程资源,避免分布式环境里大量级联失败。通过第三方客户端访问(通常是通过网络)依赖服务出现失败、拒绝、超时或短路时执行回退逻辑2.用快速失败代替排队(每个依赖服务维护一个小的线程池或信号量,当线程池满或信号量满,会立即拒绝服务而不会排队等待)和优雅的服
Easter79 Easter79
3年前
SpringCloud课程:15.Hystrix断路器简介 与 服务降级
Hystrix断路器一、概述分布式系统面临的问题复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候不可避免地失败。服务雪崩多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的“扇出效应” 如果扇出的链路上某个微服务的调用响应
Stella981 Stella981
3年前
Spring Cloud构建微服务架构
在微服务架构中,我们将系统拆分成了一个个的服务单元,各单元应用间通过服务注册与订阅的方式互相依赖。由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身问题出现调用故障或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加,最后就会出现因等待出现故障的依赖方响应而形成任务积压,线程资
Wesley13 Wesley13
3年前
C#中依赖注入
由于客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户只定义一个注入点。在程序运行过程中,客户类部直接实例化具体服务类实例,而是客户类的运行上下文环境或者专门组建负责实例化服务类,然后将其注入到客户类中,保证客户类的正常运行。依赖注入的方法大致分为3中:接口注入、构造方法注入、setter注入;1、setter注入setter注入是指
浅谈OpenStack(一)
OpenStack刚开始只有nova(计算)和swift(存储)两个核心组件,尤其是nova,几乎负责了云主机生命周期的所有操作,包括cpu、内存、磁盘、网络等,后来随着功能越来越多,项目越来越庞大,社区才把镜像管理(novaimage)服务、存储管理(novavolume)服务、网络管理(novanetwork)服务等独立出来,于是有了glance、cinder、neutron等服务。在OpenStack里有两个概念:组件和服务。我们把每个完成独立功能的项目称为一个组件,比如nova、cinder、glance、neutron。每个组件里会细分很多个服务,用来承担不同的职责,比如nova里会有novaapi服务,负责api请求的处理;novascheduler服务负责宿主机的调度;novacompute服务负责与虚拟化软件进行交互,来操作云主机。
融云IM即时通讯 融云IM即时通讯
6个月前
融云IM干货丨在Electron中实现获取历史消息,需要注意以下几点
在Electron中实现获取历史消息时,需要注意以下几点:服务开通:从远端获取单群聊历史消息需要AppKey已启用融云提供的单群聊消息云端存储服务。请在融云控制台IM服务管理页面为当前使用的AppKey开启服务。注意,仅IM旗舰版或IM尊享版可开通该服务。