转载请写明来源地址:http://blog.csdn.net/lastsweetop/article/details/60966263

Provider简单介绍

每一个web应用都是由多个对象协作完毕的。这些对象须要初始化并连接在一起为app服务。

在AngularJS中。app中的大多数对象通过injector服务初始化和连接在一起。

Injector创建两种类型的对象,service对象和特别对象。

Service对象由开发人员自己定义api。

特别对象则遵照AngularJS框架特定的api,这些对象包括:controller, directive, filter or animation。

Injector须要知道怎么样创建这些对象,你能够通过“配方”告诉它这些,总共同拥有五种“配方”。

最具体最全面的是Provider“配方”。其它四种(Value, Factory, Service and Constant)仅仅是在Provider“配方”之上包装了一下而已。

“配方”

为了使injector知道怎么样创建和链接这些对象,你须要recipe的注冊表。

每一个recipe都有一个对象的id和怎样创建对象的说明。

一个“配方”相应angularjs的一个module。module能够包括一个或者多个“配方”,module还会包括依赖于其它模块的信息。

当AngularJS使用给定的app module启动app时,angularjs会创建一个新的injector实例,injector会依次把核心module的“配方”增加“配方”注冊表。而且创建app module和他的依赖。当须要为app创建对象时,就会去查找“配方”注冊表。

让我们看下通过各种各样“配方”类型创建和使用service的场景。

在你的代码中可能多个地方须要訪问一个共享的字符串,我们先用Value“配方”来实现这样的情境。

Value“配方”

我们来创建一个非常easy的service,该service提供一个用于远程api鉴权的id字符串,能够这么写:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="uft-8"/>
<title></title>
</head>
<script src="script/angular.min.js"></script>
<body ng-controller="DemoController as demo">
Client ID: {{demo.clientId}}
</body>
<script>
var myApp = angular.module('myApp', []);
myApp.value('clientId', 'a12345654321x'); myApp.controller('DemoController', ['clientId', function DemoController(clientId) {
this.clientId = clientId;
}]);
</script>
</html>

我们创建了一个名字叫myApp的module。而且指定该module的定义包括一个构建clientId服务的recipe,这个样例中service仅仅是一个字符串。

这个样例中我们使用value“配方”定义了一个值供DemoController须要一个clientId的service时调用。

factory“配方”

Value“配方”尽管简单,可是缺少我们创建service时须要的非常多重要的功能,Factory“配方”就强大非常多,有以下功能:

  • 能够通过依赖使用其它service
  • service初始化
  • 延迟初始化

Factory“配方”能够使用0个或者多个參数创建service,这些參数能够是依赖的其它service。函数的返回值是一个通过“配方”创建的service实例。

在angularjs中全部的service都是单例的,这意味着injector为了创建对象仅仅使用每一个“配方”一次,然后injector把service的引用缓存起来。以便将来能够调用。

Factory“配方”是个更加强大的类型,因此Value“配方”能够做的事情Factory“配方”全然能够做,我们把上个样例使用Factory“配方”重写一次:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="uft-8"/>
<title></title>
</head>
<script src="script/angular.min.js"></script>
<body ng-controller="DemoController as demo">
Client ID: {{demo.clientId}}
</body>
<script>
var myApp = angular.module('myApp', []);
//myApp.value('clientId', 'a12345654321x');
myApp.factory("clientId",function(){
return "a12345654321x";
}); myApp.controller('DemoController', ['clientId', function DemoController(clientId) {
this.clientId = clientId;
}]);
</script>
</html>

如果仅仅是返回一个token这么简单,那么value“配方”则更合适,由于写起来简单也容易明确。

可是我们希望创建一个复杂点的service来计算token做远程api的身份验证,这个token叫做apiToken,通过clientId的值和浏览器本地存储中的secret值计算得出。

以上代码能够看到怎样依赖clientId服务通过Factory“配方”创建apiToken服务。

factory的函数名最好使用<serviceId>Factory形式命名,比如apiTokenFactory,当然函数名是能够不要的,可是为了调试方便还是最好写上。

同Value”配方“一样,Factory”配方“能够创建随意类型的服务。不管是原始类型。对象,函数还是自己定义的类型。

service“配方”

javascript开发人员经常喜欢写面向对象的自己定义类型,如今让我们通过unicornLauncher服务把一个unicorn发射到太空,unicornLauncher是一个自己定义类型的实例。

function UnicornLauncher(apiToken) {

  this.launchedCount = 0;
this.launch = function() {
// 使用apiToken訪问远程api
...
this.launchedCount++;
}
}

如今我们准备发射独角兽,注意到UnicornLauncher依赖于apiToken,我们通过Factory”配方“来满足这个依赖:

myApp.factory('unicornLauncher', ["apiToken", function(apiToken) {
return new UnicornLauncher(apiToken);
}]);

然而这个样例使用service“配方”更为合适

Service”配方“能够像Value”配方“和Factory“配方”一样生产service,可是它能够通过new操作符调用对象的构造函数。

构造函数的參数能够通过Service“配方中”的依赖项增加。

Service“配方”的设计模式叫做构造器注入(constructor injection)。

既然我已经有了UnicornLauncher多多构造器,我们能够把Factory”配方”替换为Service“配方”。

myApp.service('unicornLauncher', ["apiToken", UnicornLauncher]);

Provider“配方”

Provider“配方”是核心“配方”,其它全部的“配方”仅仅是在它里面加了点糖。

它是最多能力最具体的“配方”,可是对于大多数service来说。不是全部的能力都实用。

Provider“配方”定义了一个实现了$get方法的自己定义类型。$get方法是一个Factory函数,非常像Factory“配方”定义的Factory函数一样。

其实。如果你定义了一个Factory“配方”。框架会创建一个空的Provider类型。当中的$get方法就会指向你定义的Factory方法。

在app启动时。我们须要一些配合时,这个时候才会须要Provider披露的API。一般是一些能够重用的service。

默认情况下。发射器发射unicorn到太空是没有不论什么防护的。可是有些行星上大气层太厚了,在unicorn開始它的太空旅行之前。我们须要为它包裹tinfoil。否则她没通过大气层时会摩擦燃烧。

配置代码例如以下:

myApp.provider('unicornLauncher', function UnicornLauncherProvider() {
var useTinfoilShielding = false; this.useTinfoilShielding = function(value) {
useTinfoilShielding = !!value;
}; this.$get = ["apiToken", function unicornLauncherFactory(apiToken) { // 我们如果UnicornLauncher构造函数已更改,能够接收useTinfoilShielding參数
return new UnicornLauncher(apiToken, useTinfoilShielding);
}];
});

在程序启动时,config函数中调用unicornLauncherProvider的方式例如以下:

myApp.config(["unicornLauncherProvider", function(unicornLauncherProvider) {
unicornLauncherProvider.useTinfoilShielding(true);
}]);

unicornLauncherProvider是被注入到config方法中的,这里的injector和常规的实例injector不同,它仅仅负责provider的初始化和连接。

在app启动之时,在创建service之前。它会配置和实例化全部的provider,我们把这个叫做app生命周期的配置阶段,在这个阶段,service还不可使用。由于他们还未创建。

一旦配置阶段完毕,那么全部的provider变为不可用,创建service的进程開始启动,这个阶段被叫做app生命周期的执行阶段。

Constant“配方”

我们刚刚了解了怎样区分app生命周期的配置阶段和执行阶段。还有怎么样通过config函数配置app。由于配置函数在配置阶段执行,这时service都是不能够用的,它甚至无法訪问通过Value“配方”创建的简单的值对象。

有一些简单的值,比方url的前缀,没有不论什么依赖和配置,经常须要配置阶段和执行阶段都能够方便的訪问。

Constant“配方”的作用就在这了。

如果我们的unicornLauncher服务须要使用它的所在行星的名字来标记。行星的名字能够在配置阶段提供。

行星的名字对于每一个app是特定的,执行阶段会在各种各样的controller中使用。我们能够这样这样定义行星的名字作为一个常量:

myApp.constant('planetName', 'Greasy Giant');

配置unicornLauncherProvider例如以下:

myApp.config(['unicornLauncherProvider', 'planetName', function(unicornLauncherProvider, planetName) {
unicornLauncherProvider.useTinfoilShielding(true);
unicornLauncherProvider.stampText(planetName);
}]);

Constant“配方”和Value“配方”一样在配置阶段是可用的,可用用于controller和模板:

myApp.controller('DemoController', ["clientId", "planetName", function DemoController(clientId, planetName) {
this.clientId = clientId;
this.planetName = planetName;
}]);
<html ng-app="myApp">
<body ng-controller="DemoController as demo">
Client ID: {{demo.clientId}}
<br>
Planet Name: {{demo.planetName}}
</body>
</html>

特殊用途的object

之前提到有些特殊用途的对象和service是不同的,这些对象作为插件来扩展angularjs框架。须要实现angularjs指定的接口。这些接口是Controller, Directive, Filter 和 Animation。

这些特殊对象除controller外,其余的在底层其实是由Factory“配方”创建的。

在以下的样例中,我们演示怎样通过Directive的api创建一个简单的组件。这个组件依赖于我们之前定义的planetName常量,并显示这个常量:“Planet Name: Greasy Giant”

由于Directive是通过Factory“配方”注冊的,我们採用Factory同样的语法:

myApp.directive('myPlanet', ['planetName', function myPlanetDirectiveFactory(planetName) {
// directive definition object
return {
restrict: 'E',
scope: {},
link: function($scope, $element) { $element.text('Planet: ' + planetName); }
}
}]);

然后使用这个组件:

<html ng-app="myApp">
<body>
<my-planet></my-planet>
</body>
</html>

使用Factory“配方”也能够定义filter和animation,可是controller有点特殊。你能创建controller作为一个自己定义类型,它的依赖能够从它的构造函数中传入,这个构造器又被module用来注冊controller。我们来看下我之前写的DemoController:

myApp.controller('DemoController', ['clientId', function DemoController(clientId) {
this.clientId = clientId;
}]);

每次app须要DemoController实例的时候。就好调用它的构造器进行初始化。

因此和service不一样,controller不是单例的。构造器能够注入其它service。

总结

让我们来总结一下:

  • injector使用“配方”创建两种对象:service和特殊用途对象
  • 有五种“配方”能够创建对象:Value, Factory, Service, Provider, Constant.
  • Factory和Service是使用最多的“配方”。他们之间唯一的差别是:Service“配方”更适合自己定义类型的对象,而Factory“配方”更适合原生对象和函数。
  • Provider“配方”是最核心的“配方”,其它“配方”仅仅是在它上面加点糖。
  • Provider“配方”是最复杂的“配方”,除非你须要全局配置的代码,而这代码你还想不断复用。
  • 全部的特殊对象除了controller都是使用Factory“配方”创建的
Features / Recipe type Factory Service Value Constant Provider
是否能依赖与其它对象 yes yes no no yes
是否能友好的注入到其它对象 no yes yes* yes* no
创建的对象配置阶段是否可用 no no no yes yes**
是否能创建函数 yes yes yes yes yes
是否能创建原生类型 yes no yes yes yes

* 须要使用new操作符付出预先初始化的代价

** service在配置阶段不可用。可是provider对象在配置阶段可用

angular学习(十五)——Provider的更多相关文章

  1. 强化学习(十五) A3C

    在强化学习(十四) Actor-Critic中,我们讨论了Actor-Critic的算法流程,但是由于普通的Actor-Critic算法难以收敛,需要一些其他的优化.而Asynchronous Adv ...

  2. 智能车学习(十五)——K60野火2013版例程

    一.中断函数注册方法: 1.格式: 配置某个功能的中断 注册中断函数 开启中断 2.一个例子 pit_init_ms(PIT0,);//定时中断初始化 set_vector_handler(PIT0_ ...

  3. salesforce lightning零基础学习(十五) 公用组件之 获取表字段的Picklist(多语言)

    此篇参考:salesforce 零基础学习(六十二)获取sObject中类型为Picklist的field values(含record type) 我们在lightning中在前台会经常碰到获取pi ...

  4. Salesforce LWC学习(十五) Async 以及 Picklist 公用方法的实现

    本篇参考:salesforce 零基础学习(六十二)获取sObject中类型为Picklist的field values(含record type) https://developer.salesfo ...

  5. java web 学习十五(jsp基础语法)

    任何语言都有自己的语法,JAVA中有,JSP虽然是在JAVA上的一种应用,但是依然有其自己扩充的语法,而且在JSP中,所有的JAVA语句都可以使用. 一.JSP模版元素 JSP页面中的HTML内容称之 ...

  6. angular学习(五)-- Module

    1.5 模块:Module 模块定义了一个应用程序 模块是应用程序中不同部分的容器 模块是应用控制器的容器 控制器通常属于一个模块 ng 中模块的引入最重要的目的就是为了解决原来全局定义的控制器污染的 ...

  7. angular学习笔记(五)-阶乘计算实例(3)

    同样是上一个例子,我们要求并非实时的计算结果,而是等到用户确定自己已经输入完毕,然后进行计算: <!DOCTYPE html> <html ng-app> <head&g ...

  8. angular学习笔记(五)-阶乘计算实例(2)

    <!DOCTYPE html> <html ng-app> <head> <title>2.3.3计算阶乘实例2</title> <m ...

  9. angular学习笔记(五)-阶乘计算实例(1)

    <!DOCTYPE html> <html ng-app> <head> <title>2.3.2计算阶乘实例1</title> <m ...

  10. Spring 学习十五 AOP

    http://www.hongyanliren.com/2014m12/22797.html 1: 通知(advice): 就是你想要的功能,也就是安全.事物.日子等.先定义好,在想用的地方用一下.包 ...

随机推荐

  1. SQL中AND与OR的优先级

    突然发现,把基础给忘了,AND的优先级大于OR,试验如下: Oracle --Y ; --Y ) ; --No value ); 附,Oracle文档: http://docs.oracle.com/ ...

  2. Shell执行将脚本里的变量打印到指定日志文件

    首先需要定位获取任务的运行日志或者报错信息,才能定位问题. 通过shell调用有些脚本的话,日志信息会打印在shell里.不过也有用户在shell里调用正常,但是到crontab调用的时候就出错并且没 ...

  3. 【转】Hive优化总结

    优化时,把hive sql当做map reduce程序来读,会有意想不到的惊喜. 理解Hadoop的核心能力,是hive优化的根本.这是这一年来,项目组所有成员宝贵的经验总结.   长期观察hadoo ...

  4. kmp返回头位置的模板

    #include<iostream> #include<stdio.h> #include<string.h> using namespace std; char ...

  5. QQ自动发送+@好友功能+tencent://功能

    1.取出全部标题 D2007版本 procedure TForm1.Button1Click(Sender: TObject);var  hCurrentWindow:HWnd;  szText: a ...

  6. iOS 键盘处理(改变键盘为完成键),UITextField键盘显示隐藏,弹出,回弹

    很多时候用到UITextField时,处理键盘是一个很棘手的问题. 问题一:如何隐藏键盘? 方案1.改变键盘右下角的换行(enter)键为完成键,后实现代理方法键盘自动回弹 keyBoardContr ...

  7. 来自阿里的 json 解析方案 fastjson

    说起Json 解析,有非常多方法,不管是出自Google 的Gson也好,还是来自其它的某某.想必大家都非常熟悉. 今日在github上闲逛.偶遇 一 json 解析库.看起来非常不错,据说是眼下最快 ...

  8. java——关于数组的定义 和 访问修饰符的修饰内容

    public class Shuzu { public static void main(String[] args) { // 定义数组 必须初始化长度,没有初始化要放数据 int[] in = { ...

  9. iOS边练边学--九宫格布局

    一.介绍一下ViewController中的结构 二.九宫格设计思路 三.代码实现 // 点击增加按钮 - (void)add:(UIButton *)btn { // 定义一行中的列数(个数) NS ...

  10. js学习笔记12----json数据格式,语法,遍历

    1.json数据格式:var json={} 示例一: var user = {'name':'sese','age':'24','sex':'女'} console.log(user.age); / ...