AngularJS:Service、Factory、Provider依赖注入使用与区别

本篇转载于:http://blog.csdn.net/evankaka
AngularJs GitHub: https://github.com/angular/angular.js/
AngularJs下载地址:https://angularjs.org/
注:代码都亲测过,效果是一样的,所以用了作者原本的图,望谅解

AngularJs中可用来注入的有三种类型,service、factory、provide,这三种写法不一样,用法也不一样,其中,service只实例化一次,其实就是单例模式的思想,无论我们在什么地方注入service,将永远使用同一个实例,所以对很多Controller的操作就可以放到service层中去。
AngularJS提供例如许多的内在服务,如:$http$route$window,$location等等。每个服务负责例如一个特定的任务,$http是用来创建AJAX调用,已获得服务器的数据。$route用来定义路由信息等。内置的服务总是前缀$符号。
关系图如下所示:

image.png

一、Service使用详解
(1)定义
一般使用this来操作数据、定义函数。

app.service('myService', function () {
    var privateValue='I am priivate';
    this.variable = 'This is public';
    this.getPrivate = function(){
        return privateValue;
    };
});

(2)AngularJS中使用DI添加Service的三种方式
方式1(内联注解,推荐使用)

app.controller('myController',['$scope','deteFiler',function($scope,deteFilter){}]);

方式2($inject注解)

var MyController = function($scope,dateFilter){}
MyController.$inject =['$scope','dateFilter'];
someModule.controller('MyController',MyController);

方式3 (隐式注解、不推荐使用);

app.controller('mycontroller',function($scope,dateFilter){});

推荐使用方法1的理由是:
写法上比方法2更简单明了,比方法3更可靠(由于JavaScriptkeyi可以被压缩,AngularJs又是通过解析服务器名称找到对应的Service的,因为JavaScript压缩之后AngularJs将无法找到指定的Service,但字符串不会被压缩,因此单独以字符串指定的Service的名称可以避免这个问题)
使用方法1或方法2的注意点:
由于上述第二点原因:AngularJS在编译Htm时,由$injector将数组中的service的名称与方法中的Service进行--映射。这种映射关系必须遵循由AngularJS的约定:
数组中Service名称的个数必须与方法体中Service名称个数一致
数组中Service的顺序必须与方法体中Service的顺序一致。

(3)什么时候适合使用Service()方法
Service()方法很适合使用在功能控制比较多的Service()里面
*需要使用.config()来配置service的时候不能使用service()方法
(4)service使用实例

<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
    <meta charset="UTF-8">
    <title>AngularJs学习</title>
    <script type="text/javascript" src="js/angular.min.js"></script>
</head>
<body>
    <div ng-controller="MyCtrl">
        <button ng-click="getPrivate()">按钮一</button>
        <button ng-click="getPublic()">按钮二</button>
    </div>
    <div ng-controller="MyCtrl2"></div>
</body>
<script type="text/javascript">
    var app = angular.module('myApp', []);
    app.controller('MyCtrl',function ($scope,myService) {
        $scope.getPrivate = function(){
            alert(myService.getPrivate());
        };
        $scope.getPublic = function(){
            alert(myService.variable);
        };
    });
    app.controller('MyCtrl2',function ($scope,myService) {  
    });
    app.service('myService', function () {
        console.log('instance myService');
        var privateValue = 'I am private';
        this.variable = 'This is public';
        this.getPrivate=function(){
            return privateValue;
        }
    });
</script>
</html>

效果如下:

image.gif

另外,从控制台可以看出两个Controller注入了同一个Service,但最终只实例化了一次。
image.png

service定义的服务不能在.config中使用!只有providerdingyi定义的才可以

二、Factory使用详解
Factory一般就是创建一个对象。然后在这个对象添加方法与数据,最后将些对象返回即可,然后注入到Controller层中即可。
使用实例:

<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
    <meta charset="UTF-8">
    <title>AngularJs学习</title>
    <script type="text/javascript" src="js/angular.min.js"></script>
</head>
<body>
    <div ng-controller="MyCtrl">
        <button ng-click="getPrivate()">按钮一</button>
        <button ng-click="getPublic()">按钮二</button>
    </div>
    <div ng-controller="MyCtrl2"></div>
</body>
<script type="text/javascript">
    var app = angular.module('myApp', []);
    app.controller('MyCtrl',function ($scope,myFactory) {
        $scope.getPrivate = function(){
            alert(myFactory.getPrivate());
        };
        $scope.getPublic = function(){
            alert(myFactory.variable);
        };
    });
    app.controller('MyCtrl2',function ($scope,myFactory) {  
    });
    app.factory('myFactory', function () {
        console.log('instance myFactory');
        var privateValue = 'I am private';
        this.variable = 'This is public';
        this.getPrivate=function(){
            return privateValue;
        };
        return factory;
    });
</script>
</html>

效果如下:


image.gif

另外,从这里可以看到controller注入同一个factory,但是最终只实例化了一次。


image.png

记住一定要return 一个Object对象,否则会报出一下错误。
image.png

三、provider使用详解
$provide服务负责告诉AngularJs如何r创造一个新的可注入的东西,即服务。服务会被叫做供应商的东西来定义,你可以使用$provide来创建一个供应商。你需要使用$provide中的provider()方法来定义一个供应商,同时也可以通过要求$provide被注入到一个引用的config函数中来获得$provide服务,使用方法是返回一个$get函数,注意的是,在config阶段,只有provider能被注入,其他用法和service一样。
实例:

<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
    <meta charset="UTF-8">
    <title>AngularJs学习</title>
    <script type="text/javascript" src="js/angular.min.js"></script>
</head>
<body>
    <div ng-controller="myCtrl1">
        <button ng-click="onclick1()">请点击我1</button>
    </div>
    <div ng-controller="myCtrl2">
        <button ng-click="onclick2()">请点击我2</button>
    </div>
</body>
<script type="text/javascript">
    var app = angular.module('myApp', []);
    app.controller('myCtrl1', function ($scope , testProvider) {
        $scope.onclick1=function(){
            testProvider("林炳文Evankaka");
        };
    });

    app.controller('myCtrl2',function ($scope , testProvider) {
        $scope.onclick2 = function(){
            testProvider("我到底是谁");
        };
    });

    app.provider('testProvider', function () {
        console.log('instance testProvider');
        var f = function(name){
            alert("hello,"+name);
        }
        this.$get = function() {
            return f;
        };
    });
</script>
</html>

效果如下:


image.gif

控制台输出内容:


image.png

下面是一个provider实例化的时间测试

<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
    <meta charset="UTF-8">
    <title>AngularJs学习</title>
    <script type="text/javascript" src="js/angular.min.js"></script>
</head>
<body>
    <div ng-controller="myCtrl1">
        <button ng-click="onclick1()">请点击我1</button>
    </div>
    <div ng-controller="myCtrl2">
        <button ng-click="onclick2">请点击我2</button>
    </div>
</body>
<script type="text/javascript">
    var app = angular.module('myApp', []);

    app.controller('myCtrl1',function ($scope) {
        // $scope.onclick1 = function(){
        //  test("林炳文Evankaka");
        // };
    });
    app.controller('myCtrl2', function ($scope) {
        // $scope.onclick2 = function(){
        //  test("我到底是谁");
        // };
    });

    // app.config(function (testProvider) {
    //  testProvider('I am config');
    // });

    app.provider('test', function () {
        console.log('instance test')
        var f = function(name){
            alert("hello,"+name);
        }

        this.$get = function() {
            return f;
        };
    });

    app.config(function ($provide) {
        $provide.provider('greetting', function(){
            this.$get = function(){
                return function(name){
                    alert('hello,'+name);
                }
            }
        });
        // greetingProvider('ff');
    });
</script>
</html>
image.png

页面刷新后,即使不注入provider,但它也进行了实例化,而Service/Factory则是第一次注入时才会初始化。而这也是为什么它可以注入到config的一个原因吧。

什么时候使用provider() 方法
(1)当我们希望在应用开始前对Service进行配置的时候就需要使用到provider().。比如,我们需要配置Service在不同的部署环境(开发,演示,生产)使用不同的后端处(2)理的时候,就可以使用到了,当我们打算发布开源provider()也是首选创建service的方法,这样就可以使用配置的方法来配置Services而不是将配置数据硬编码写到代码里。

四、Service、Factory、Provider三者的区别

(1)用Factory就是创建一个对象,为它添加属性,然后把这个对象返回出来。把Service传进Controller之后,在Controller里这个对象的属性就可以通过factory使用了。
(2)Service是用new关键字实例化的。因此,应该给this添加属性。然后service返回this,把service传进Controller之后,在Controller里this上的属性就可以通过Service来使用了。
(3)providers是唯一一种可以传入.config()函数的Service。当想要在Service对象启用之前,先进性模块范围的配置,那就应该使用provider
(4)Factory/service是第一个注入时才实例化。而provider不是,它是在config之前就实例化好了。
同一种函数的三种不同写法:

<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
    <meta charset="UTF-8">
    <title>AngularJs学习</title>
    <script type="text/javascript" src="js/angular.min.js"></script>
</head>
<body>
    <div ng-controller="myCtrl1">
        <p>{{ output1 }}</p>
        <p>{{ output2 }}</p>
        <p>{{ output3 }}</p>
    </div>
    <div ng-controller="myCtrl2"></div>
</body>
<script type="text/javascript">
    var app = angular.module('myApp', []);
    app.controller('myCtrl1', function ($scope,testService,testFactory,testProvider) {
        $scope.output1 = testService.lable;
        $scope.output2 = testFactory.lable();
        $scope.output3 = testProvider;
    });

    app.controller('myCtrl2', function ($scope,testService,testFactory,testProvider) {
        
    });

    app.service('testService', function () {
        console.log('instance testService');
        this.lable = 'this is service'; 
    });

    app.factory('testFactory', function () {
        console.log('instance testFactory');    
    
        return {
            lable:function(){
                return 'this is factory';
            }
        };
    });

    app.provider('testProvider', function () {
        console.log('instance testProvider');
        
        this.$get = function() {
            return 'this is provider';
        };
    });
</script>
</html>
image.png

看console的输出,可以知道都只实例 化了一次:


image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,198评论 6 514
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,334评论 3 398
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,643评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,495评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,502评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,156评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,743评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,659评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,200评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,282评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,424评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,107评论 5 349
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,789评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,264评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,390评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,798评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,435评论 2 359

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,693评论 18 139
  • 1.背景介绍 依赖注入式AngularJS的重要特性之一,依赖注入简化了Angular解析模块/组件之间依赖的过程...
    你隔壁的陌生人阅读 649评论 0 1
  • 大家好,我是IT修真院郑州分院,一枚正直、纯洁、善良的web程序员。 今天给大家分享一下,修真院官网 CSS任务中...
    初晨晒暖心阅读 1,144评论 0 1
  • 在Angular中,控制器应该是简洁精炼的;一些逻辑和重复性的数据都应该要存储到服务中。控制器就应该在需要他们的时...
    aaronckl阅读 1,000评论 0 0
  • 抱歉开了两天天窗 这两天干嘛了 去看了韩剧太阳的后裔 瞧 像不像温水煮青蛙这个预言中的青蛙 明明现实生活什么都没做...
    二京阅读 249评论 0 0