对服务与工厂感到困惑


618

据我了解,当在工厂内部时,我返回一个注入到控制器中的对象。在服务内部时,我使用this而不是返回任何东西来处理对象。

我当时以为服务始终是单例,并且每个控制器都注入了一个新的工厂对象。但是,事实证明,工厂对象也是单例吗?

示例代码演示:

var factories = angular.module('app.factories', []);
var app = angular.module('app',  ['ngResource', 'app.factories']);

factories.factory('User', function () {
  return {
    first: 'John',
    last: 'Doe'
  };
});

app.controller('ACtrl', function($scope, User) {
  $scope.user = User;
});

app.controller('BCtrl', function($scope, User) {
  $scope.user = User;
});

当改变user.firstACtrl事实证明,user.firstBCtrl也发生了变化,比如User是一个单身?

我的假设是在工厂的控制器中注入了新实例?


4
在“ module.service”和“ module.factory”旁边,还有两种在AngularJS中创建服务的方法。有关更多信息,请查看博客文章:“ 如何以4种不同方式创建(单例)AngularJS服务
Emil van Galen 2013年

Answers:


600

所有角度服务都是单例

Docs(请参阅Services作为单例):https : //docs.angularjs.org/guide/services

最后,重要的是要意识到所有Angular服务都是应用程序单例。这意味着每个喷油器只有一种给定服务的实例。

基本上,服务和工厂之间的区别如下:

app.service('myService', function() {

  // service is just a constructor function
  // that will be called with 'new'

  this.sayHello = function(name) {
     return "Hi " + name + "!";
  };
});

app.factory('myFactory', function() {

  // factory returns an object
  // you can run some code before

  return {
    sayHello : function(name) {
      return "Hi " + name + "!";
    }
  }
});

查看有关$ provide的此演示文稿:http : //slides.wesalvaro.com/20121113/#/

这些幻灯片用于AngularJs聚会之一:http : //blog.angularjs.org/2012/11/more-angularjs-meetup-videos.html


13
另请参阅stackoverflow.com/questions/15666048/…,其中讨论了服务,工厂和提供之间的区别。
Mark Rajcok

31
官方文档间接[原文如此![不够不够清晰]表示即使您使用工厂定义服务,也只能创建一次。换句话说,无论您怎么称呼它,它都不会根据参考(注入点)再次创建。两种方式都会导致每个注入器具有单例实例。
honzajde

3
您说“服务只是一个将被'new'调用的构造函数”,但我认为这具有误导性。我不认为它是在幕后调用的,我认为开发人员有责任对此进行调用new
Tim Kindberg

5
@nfiniteloop,检查3574行附近的源代码。工厂是提供程序的$ get方法,服务使用在提供的函数上调用$ injector.instantiate的方法生成工厂,然后调用new。(请参阅Google文档
公民

14
我给人的印象是,通过引用服务,您就可以使用它。而且工厂是一个单例,每次都会返回一个新对象。也就是说,一项服务将为您提供一辆“汽车”,而您项目中的所有内容都将使用该汽车。每次您调用工厂时,工厂都会为您提供一辆新车。一个是单例返回一个单例,一个是单例返回一个对象。谁能解释?将所有内容都称为单例并没有帮助,因为它可以引用多个内容。
user2483724 2014年

380

对我而言,当我意识到它们都以相同的方式工作时,就会发现:通过运行一次,存储它们获得的值,然后在通过依赖注入进行引用时咳出相同的存储值

说我们有:

app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);

两者之间的区别在于:

  1. a的储值来自运行fn,换句话说:fn()
  2. b的储值来自newing fn,换句话说:new fn()
  3. c的存储值来自首先通过newing 获取实例fn,然后运行$get该实例的方法

这意味着,在angular中有一个类似于缓存的对象,每次注入的值仅在第一次注入时分配一次,其中:

cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()

这就是为什么我们this在服务中使用并定义this.$getin提供程序的原因。

希望这可以帮助。


54
最后,一个理智的解释。Angular太疯狂了,非常糟糕,以至于令人痛心。
osiris

8
这应该是公认的答案,因为它实际上回答了为什么工厂,服务和提供者返回单例值的问题。其他答案解释了工厂,服务和提供者之间的区别,但从未涉及单例方面。
wmock 2015年

3
我喜欢这样...当我从其他博主那里读了一千行句子时,我只能理解工厂。不过,我看到这个...我明白所有的3
tsohtan

@osiris我同意。我不喜欢 感觉太紧了,以至于我的牙齿都磨了。
托马斯

2
因此使用提供程序时必须提供$ get的实现?
维克多

95

现场例子

“你好世界”的例子

factory/ service/ provider

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

//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
    this.sayHello = function() {
        return "Hello, World!"
    };
});

//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
    return {
        sayHello: function() {
            return "Hello, World!"
        }
    };
});

//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() {
    // In the provider function, you cannot inject any
    // service or factory. This can only be done at the
    // "$get" method.

    this.name = 'Default';

    this.$get = function() {
        var name = this.name;
        return {
            sayHello: function() {
                return "Hello, " + name + "!"
            }
        }
    };

    this.setName = function(name) {
        this.name = name;
    };
});

//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider){
    helloWorldProvider.setName('World');
});


function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {

    $scope.hellos = [
        helloWorld.sayHello(),
        helloWorldFromFactory.sayHello(),
        helloWorldFromService.sayHello()];
}​

57

还有一种返回构造函数的方法,因此您可以在工厂中返回可更新的类,如下所示:

function MyObjectWithParam($rootScope, name) {
  this.$rootScope = $rootScope;
  this.name = name;
}
MyObjectWithParam.prototype.getText = function () {
  return this.name;
};

App.factory('MyObjectWithParam', function ($injector) {
  return function(name) { 
    return $injector.instantiate(MyObjectWithParam,{ name: name });
  };
}); 

因此,您可以在使用MyObjectWithParam的控制器中执行此操作:

var obj = new MyObjectWithParam("hello"),

参见完整示例:http :
//plnkr.co/edit/GKnhIN?p=preview

在这里讨论过的Google网上论坛页面:https//groups.google.com/forum/#! msg / angular / 56sdORWEoqg /
b8hdPskxZXsJ


我在使用您的示例进行缩小方面遇到问题。你知道我该怎么注释吗?
2014年

2
是的,有一个最小化的Angular表示法。它应该是这样的: App.factory('MyObjectWithParam', ['$injector', function ($injector) { return function(name) { return $injector.instantiate(MyObjectWithParam,{ name: name }); }; }]); 在此处了解更多信息: docs.angularjs.org/tutorial/step_05
JustGoscha 2014年

4
如果可以使用,为什么还要这么做.service呢?
flup

我有同样的想法@flup。@justgoscha,是有一些好处(percieved?使用的).factory,而不是.service
xandercode

5
我认为因为服务是单身人士。我在这里构造的基本上是一个可更新的类。因此,您可以拥有一家汽车维修厂,然后进行制造new Car('BMW')new Car('Ford')而它们却不会共享相同的变量和所有内容。
JustGoscha 2015年

51

主要区别如下:

服务

句法: module.service( 'serviceName', function );

结果:将serviceName声明为可注入参数时,将为您提供传递给的函数实例module.service

用法:对于共享实用程序函数很有用,这些函数只需将()附加到注入的函数引用中即可调用。也可以与之injectedArg.call( this )类似地运行。

工厂工厂

句法: module.factory( 'factoryName', function );

结果:当将factoryName声明为可注入参数时,将通过调用传递给的函数引用来提供返回module.factory

用法:对于返回“类”函数很有用,然后可以对其进行新的创建实例。

另请查看AngularJS文档以及关于服务与工厂混淆的关于 stackoverflow的类似问题。

这是使用services和factory的示例。了解有关AngularJS服务与工厂的更多信息。


6
这对我来说很有意义。工厂将返回创建新对象的蓝图。

27

除了第一个答案外,我认为.service()适用于以更加面向对象的风格(C#/ Java)(使用此关键字并通过prototype / Constructor函数实例化对象)编写代码的人。

Factory适用于编写代码的开发人员,这些代码对于javascript /功能代码风格更自然。

看一下angular.js内的.service和.factory方法的源代码-内部它们都调用provider方法:

  function provider(name, provider_) {
    if (isFunction(provider_)) {
      provider_ = providerInjector.instantiate(provider_);
    }
    if (!provider_.$get) {
      throw Error('Provider ' + name + ' must define $get factory method.');
    }
    return providerCache[name + providerSuffix] = provider_;
  }

  function factory(name, factoryFn) { \
    return provider(name, { $get: factoryFn }); 
  }

  function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
  }

25

很简单:

.service注册的函数将作为构造函数调用(也称为“新的”)

.factory注册的函数将作为一个简单函数被调用

两者都被调用一次,导致一个单例对象被注入到应用程序的其他组件中。


6
是。让我们不要让事情变得比实际复杂得多
flup 2015年

20

所有提供程序都以相同的方式工作。不同的方法servicefactoryprovider只是让你完成同样的事情在更少的代码。

PS还有valueconstant

链中开始provider和结束的每个特殊情况value都有一个附加的限制。因此,要在它们之间做出决定,您必须问自己一个问题,即可以用更少的代码来完成所需的工作。

这是一张图片,向您展示我的意思:

在此处输入图片说明

您可以在我从以下图片中获得的博客文章中获得细分和参考指南:

http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/


据说服务是单例的,但是如果每次我注入新实例时都会创建单例,那它又是单例的呢?
Ankur Marwaha

1
@AnkurMarwaha不会每次都创建一个新实例,它只会创建一次并由AngularJS缓存。无论您使用的是提供者,工厂,服务等,都是如此。您可以使用console.log()并注入多个控制器来确认这一点。
路易斯·佩雷斯

路易斯,您的评论与公认的答案相抵触-最后,重要的是要意识到所有Angular服务都是应用程序单例。这意味着每个喷油器只有一种给定服务的实例。
Ankur Marwaha

@AnkurMarwaha也许我误会了一些东西。您引用了“认识到所有Angular服务都是应用程序单例很重要”-它们是单例这一事实意味着它们仅创建一次。这就是我所说的“ 每次不会创建一个新实例,它只会创建一次并缓存...”。您能否详细指出冲突发生的地方?
路易斯·佩雷斯

1
啊,我看到了混乱。“喷射器”是成角度的物体。它负责执行“注射”。例如,当控制器第一次运行时,“注入器”查看参数并注入每个参数。整个应用程序只有一个“注入器”。一旦注入器创建了特定的工厂或服务,它就会保留一个实例并重新使用它-因此是单例。因此,每个应用程序只有一个注入器,每个注入器只有给定服务的一个实例。大多数应用程序角只有一个应用程序,因此一个注射器,因此任何服务的一个实例,控制器等
路易斯·佩雷斯

13

这里是服务与工厂的更多示例,可能有助于了解它们之间的区别。基本上,服务已调用了“ new ...”,它已被实例化。工厂不会自动实例化。

基本范例

返回具有单个方法的类对象

这是一种具有单一方法的服务:

angular.service('Hello', function () {
  this.sayHello = function () { /* ... */ };
});

这是一个使用方法返回对象的工厂:

angular.factory('ClassFactory', function () {
  return {
    sayHello: function () { /* ... */ }
  };
});

返回值

返回数字列表的工厂:

angular.factory('NumberListFactory', function () {
  return [1, 2, 3, 4, 5];
});

console.log(NumberListFactory);

返回数字列表的服务:

angular.service('NumberLister', function () {
  this.numbers = [1, 2, 3, 4, 5];
});

console.log(NumberLister.numbers);

两种情况下的输出都是相同的,即数字列表。

进阶范例

使用工厂的“类”变量

在此示例中,我们定义了一个CounterFactory,它使一个计数器递增或递减,您可以获取当前计数或获取创建了多少CounterFactory对象:

angular.factory('CounterFactory', function () {
  var number_of_counter_factories = 0; // class variable

  return function () {
    var count = 0; // instance variable
    number_of_counter_factories += 1; // increment the class variable

    // this method accesses the class variable
    this.getNumberOfCounterFactories = function () {
      return number_of_counter_factories;
    };

    this.inc = function () {
      count += 1;
    };
    this.dec = function () {
      count -= 1;
    };
    this.getCount = function () {
      return count;
    };
  }

})

我们使用CounterFactory创建多个计数器。我们可以访问类变量以查看创建了多少个计数器:

var people_counter;
var places_counter;

people_counter = new CounterFactory();
console.log('people', people_counter.getCount());
people_counter.inc();
console.log('people', people_counter.getCount());

console.log('counters', people_counter.getNumberOfCounterFactories());

places_counter = new CounterFactory();
console.log('places', places_counter.getCount());

console.log('counters', people_counter.getNumberOfCounterFactories());
console.log('counters', places_counter.getNumberOfCounterFactories());

此代码的输出是:

people 0
people 1
counters 1
places 0
counters 2
counters 2

这是一个有用的示例,number_of_counter_factories就像是CounterFactory类的元属性,对吗?我知道此示例可在服务上复制(如果我错了,请告诉我),这种情况下的语义差异是什么?
geoom

有用的例子!因此,这基本上意味着在工厂中,您可以拥有服务中无法获得的额外抽象层。无论返回什么,只要使用“ new”,都将返回它的新实例。未在return块内声明的任何变量均为单例。我说对了吗?
斯瓦尼迪2015年

@Swanidhi基本上是的,您可以在工厂中声明单例变量。这就是为什么我称它们为“类”变量。

13

“工厂”和“服务”是进行角度DI(依赖注入)的不同方式。

因此,当我们使用“服务”定义DI时,如以下代码所示。这将创建“ Logger”对象的新GLOBAL实例,并将其注入到函数中。

app.service("Logger", Logger); // Injects a global object

使用“工厂”定义DI时,它不会创建实例。它只是传递了方法,后来,使用者内部必须调用工厂的对象实例。

app.factory("Customerfactory", CreateCustomer);

下面是一个简单的图像,直观地显示了“服务”的DI处理与“工厂”的区别。

在此处输入图片说明

当我们要根据场景创建不同类型的对象时,应使用Factory。例如,根据情况,我们要创建一个简单的“客户”对象,或者创建“地址”对象的“客户”对象,或者创建“电话”对象的“客户”对象。这是本段的详细说明

当我们有实用程序或共享功能要注入时,应该使用Service,例如Utility,Logger,Error handler等。


我在这个问题上看到的每个答案以及类似的答案都在说明机制和语法上的差异。这个答案给出了为什么您要选择一个而不是另一个的真实原因。这是一个语义问题,需要查看名称,服务或工厂,以传达其目的和使用方式。
Joe Mayo

8

服务风格:(可能是最简单的一种)返回实际函数:对于共享实用程序函数很有用,只需将()附加到注入的函数引用上即可调用这些函数。

AngularJS中的服务是一个单例JavaScript对象,其中包含一组函数

var myModule = angular.module("myModule", []);

myModule.value  ("myValue"  , "12345");

function MyService(myValue) {
    this.doIt = function() {
        console.log("done: " + myValue;
    }
}

myModule.service("myService", MyService);
myModule.controller("MyController", function($scope, myService) {

    myService.doIt();

});

工厂样式:(涉及更多但更复杂)返回函数的返回值:在Java中实例化诸如new Object()之类的对象。

Factory是创建值的函数。当服务,控制器等需要从工厂注入的值时,工厂将按需创建值。创建后,该值可用于需要注入的所有服务,控制器等。

var myModule = angular.module("myModule", []);

myModule.value("numberValue", 999);

myModule.factory("myFactory", function(numberValue) {
    return "a value: " + numberValue;
})  
myModule.controller("MyController", function($scope, myFactory) {

    console.log(myFactory);

});

提供程序样式:(完整版本,可配置)返回函数$ get函数的输出:可配置。

AngularJS中的提供者是您可以创建的最灵活的工厂形式。您可以像使用服务或工厂一样向模块注册提供程序,只是使用provider()函数代替。

var myModule = angular.module("myModule", []);

myModule.provider("mySecondService", function() {
    var provider = {};
    var config   = { configParam : "default" };

    provider.doConfig = function(configParam) {
        config.configParam = configParam;
    }

    provider.$get = function() {
        var service = {};

        service.doService = function() {
            console.log("mySecondService: " + config.configParam);
        }

        return service;
    }

    return provider;
});

myModule.config( function( mySecondServiceProvider ) {
    mySecondServiceProvider.doConfig("new config param");
});

myModule.controller("MyController", function($scope, mySecondService) {

    $scope.whenButtonClicked = function() {
        mySecondService.doIt();
    }

});

詹科夫

<!DOCTYPE html>
    <html ng-app="app">
    <head>
    	<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
    	<meta charset=utf-8 />
    	<title>JS Bin</title>
    </head>
    <body ng-controller="MyCtrl">
    	{{serviceOutput}}
    	<br/><br/>
    	{{factoryOutput}}
    	<br/><br/>
    	{{providerOutput}}
    
    	<script>
    
    		var app = angular.module( 'app', [] );
    
    		var MyFunc = function() {
    
    			this.name = "default name";
    
    			this.$get = function() {
    				this.name = "new name"
    				return "Hello from MyFunc.$get(). this.name = " + this.name;
    			};
    
    			return "Hello from MyFunc(). this.name = " + this.name;
    		};
    
    		// returns the actual function
    		app.service( 'myService', MyFunc );
    
    		// returns the function's return value
    		app.factory( 'myFactory', MyFunc );
    
    		// returns the output of the function's $get function
    		app.provider( 'myProv', MyFunc );
    
    		function MyCtrl( $scope, myService, myFactory, myProv ) {
    
    			$scope.serviceOutput = "myService = " + myService;
    			$scope.factoryOutput = "myFactory = " + myFactory;
    			$scope.providerOutput = "myProvider = " + myProv;
    
    		}
    
    	</script>
    
    </body>
    </html>

jsbin

<!DOCTYPE html>
<html ng-app="myApp">
<head>
	<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
	<meta charset=utf-8 />
	<title>JS Bin</title>
</head>
<body>
<div ng-controller="MyCtrl">
    {{hellos}}
</div>
	<script>

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

//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
    this.sayHello = function() {
        return "Hello, World!"
    };
});

//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
    return {
        sayHello: function() {
            return "Hello, World!"
        }
    };
});
    
//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() {

    this.name = 'Default';

    this.$get = function() {
        var name = this.name;
        return {
            sayHello: function() {
                return "Hello, " + name + "!"
            }
        }
    };

    this.setName = function(name) {
        this.name = name;
    };
});

//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider){
    helloWorldProvider.setName('World');
});
        

function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {
    
    $scope.hellos = [
        helloWorld.sayHello(),
        helloWorldFromFactory.sayHello(),
        helloWorldFromService.sayHello()];
}
	</script>

</body>
</html>

jsfiddle


2

基本区别在于,provider允许将原始(非对象),数组或回调函数值设置为工厂声明的变量,因此,如果返回对象,则必须明确声明并返回。

另一方面,服务只能用于将服务声明的变量设置为对象,因此我们可以避免显式创建和返回对象,而另一方面,它允许使用this关键字。

简而言之,“ 提供者是一种更通用的形式,而服务仅限于对象”。


2

这就是我理解它们在设计模式方面的区别的方式:

服务:返回一种类型,将对其进行更新以创建该类型的对象。如果使用Java类比,则Service返回Java类定义

工厂:返回可以立即使用的具体对象。在Java类比中,工厂返回一个Java对象

通常会使人们(包括我自己)感到困惑的部分是,当您在代码中注入服务或工厂时,它们可以以相同的方式使用,两种情况下您在代码中得到的都是可以立即调用的具体对象。这意味着在服务的情况下,角度服务代表您在服务声明中调用“ new”。我认为这是一个令人费解的概念。


1

这将是理解服务与工厂与提供商的最佳和简短的答案

来源https : //groups.google.com/forum/#! msg / angular/ 56sdORWEoqg / HuZsOsMvKv4J

这是Ben演示中 说的内容http://jsbin.com/ohamub/1/edit?html,输出

“代码中有注释说明了主要差异,但在这里我将对其进行一些扩展。请注意,我只是想着要解决这个问题,因此,如果我说错了什么,请告诉我。

服务

语法:module.service('serviceName',function);

结果:将serviceName声明为可注入参数时,将为您提供传递给module.service的实际函数引用。

用法:对于共享实用程序功能很有用,这些功能只需将()附加到注入的函数引用上,即可调用。也可以使用injectedArg.call(this)或类似方法运行。

工厂工厂

句法:module.factory('factoryName',function);

结果:当将factoryName声明为可注入参数时,将通过调用传递给module.factory的函数引用为您提供返回的值。

用法:对于返回“类”函数很有用,然后可以对其进行新的创建实例。

提供者

句法:module.provider('providerName',function);

结果:当将providerName声明为可注入参数时,将通过调用传递给module.provider的函数引用的$ get方法为您提供返回的值。

用法:对于返回一个“类”函数很有用,该函数可以被新建以创建实例,但是在注入之前需要某种配置。对于在项目间可重用的类也许有用?对此仍然有些朦胧。” Ben


1

我有一段时间的困惑,我正在尽力在这里提供一个简单的解释。希望这会有所帮助!

angular .factoryangular .service两个用于初始化以同样的方式服务和工作。

唯一的区别是,您要如何初始化服务。

都是单身人士


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


app.factory(<service name><function with a return value>

如果您想从具有返回值的函数中初始化服务,则必须使用此factory方法。

例如

function myService() {
  //return what you want
  var service = {
    myfunc: function (param) { /* do stuff */ }
  }
  return service;
}

app.factory('myService', myService);

注入此服务时(例如,向您的控制器):

  • Angular将调用您的给定函数(如myService())以返回对象
  • 单例 -仅调用一次,存储并传递同一对象。


服务

app.service(<service name><constructor function>

如果要通过构造函数(使用this关键字)初始化服务,则必须使用此service方法。

例如

function myService() {
  this.myfunc: function (param) { /* do stuff */ }
}

app.service('myService', myService);

注入此服务时(例如,向您的控制器):

  • Angular将使用new给定的函数(如new myService())返回对象
  • 单例 -仅调用一次,存储并传递同一对象。


注意:如果factory<constructor function>service一起使用<function with a return value>,则将无法使用。


示例-演示


1

多亏了Pascal Precht的博客文章,这才帮助我理解了差异。

服务是模块上的方法,该方法采用名称和定义服务的函数。您可以在其他组件(例如控制器,指令和过滤器)中注入并使用该特定服务。工厂是模块上的一种方法,它还使用一个名称和一个函数来定义工厂。我们还可以像使用服务一样注入和使用它。

使用new创建的对象使用其构造函数的prototype属性的值作为其原型,因此我找到了调用Object.create()的Angular代码,我相信它在实例化时就是服务构造函数。但是,工厂函数实际上只是一个被调用的函数,这就是为什么我们必须为工厂返回对象文字的原因。

这是我为工厂找到的角度1.5代码:

var needsRecurse = false;
    var destination = copyType(source);

    if (destination === undefined) {
      destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
      needsRecurse = true;
    }

factory()函数的角度源代码片段:

 function factory(name, factoryFn, enforce) {
    return provider(name, {
      $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
    });
  }

它使用名称和传递的工厂函数,并返回具有相同名称的提供程序,该提供程序具有$ get方法,这是我们的工厂函数。每当您向注入程序询问特定的依赖关系时,它基本上都会通过调用$ get()方法向相应的提供程序询问该服务的实例。这就是创建提供程序时需要$ get()的原因。

这是服务的角度1.5代码。

function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
  }

事实证明,当我们调用service()时,它实际上调用了factory()!但是,它不只是将我们的服务构造函数原样传递给工厂。它还传递一个函数,该函数要求注入器通过给定的构造函数实例化一个对象。

换句话说,如果我们将MyService注入某处,代码中将发生以下情况:

MyServiceProvider.$get(); // return the instance of the service

要再次声明它,服务将调用工厂,这是相应提供程序上的$ get()方法。此外,$ injector.instantiate()是最终使用构造函数调用Object.create()的方法。这就是为什么我们在服务中使用“ this”的原因。

对于ES5,我们使用哪个无关紧要:service()或factory(),始终是一个被调用的工厂,它将为我们的服务创建提供程序。

但是,您也可以对服务执行完全相同的操作。服务是构造函数,但是,这不能阻止我们返回对象文字。因此,我们可以采用服务代码并以与工厂基本相同的方式编写服务代码,换句话说,您可以将服务编写为工厂以返回对象。

为什么大多数人建议使用工厂而不是服务?这是我见过的最好的答案,来自Pawel Kozlowski的书:用AngularJS掌握Web应用程序开发。

工厂方法是将对象放入AngularJS依赖注入系统的最常用方法。它非常灵活,可以包含复杂的创建逻辑。由于工厂是常规函数,因此我们还可以利用新的词汇范围来模拟“私有”变量。这非常有用,因为我们可以隐藏给定服务的实现细节。”


1
  • 工厂中,您实际上是在工厂内部创建一个对象并将其返回。
  • 使用该服务,您只有一个使用关键字定义功能的标准 this功能。
  • 有了提供者$get您可以定义它,它可以用于获取返回数据的对象。

1

AngularJS中有三种处理业务逻辑的方式:(受Yaakov的Coursera AngularJS课程启发),它们是:

  1. 服务
  2. 提供者

在这里,我们只讨论服务工厂

服务内容

句法:

app.js

 var app = angular.module('ServiceExample',[]);
 var serviceExampleController =
              app.controller('ServiceExampleController', ServiceExampleController);
 var serviceExample = app.service('NameOfTheService', NameOfTheService);

 ServiceExampleController.$inject = ['NameOfTheService'] //very important as this protects from minification of js files

function ServiceExampleController(NameOfTheService){
     serviceExampleController = this;
     serviceExampleController.data = NameOfTheService.getSomeData();
 }

function NameOfTheService(){
     nameOfTheService = this;
     nameOfTheService.data = "Some Data";
     nameOfTheService.getSomeData = function(){
           return nameOfTheService.data;
     }     
}

index.html

<div ng-controller = "ServiceExampleController as serviceExample">
   {{serviceExample.data}}
</div>

服务的主要特点:

  1. 延迟实例化:如果未注入服务,则永远不会实例化。因此,要使用它,您必须将其注入模块。

  2. 单例:如果将其注入到多个模块中,则所有人都只能访问一个特定实例。这就是为什么在不同的控制器之间共享数据非常方便。

现在让我们谈谈AngularJS中的Factory

首先让我们看一下语法

app.js

var app = angular.module('FactoryExample',[]);
var factoryController = app.controller('FactoryController', FactoryController);
var factoryExampleOne = app.factory('NameOfTheFactoryOne', NameOfTheFactoryOne);
var factoryExampleTwo = app.factory('NameOfTheFactoryTwo', NameOfTheFactoryTwo);

//first implementation where it returns a function
function NameOfTheFactoryOne(){
   var factory = function(){
      return new SomeService();
    }
   return factory;
}

//second implementation where an object literal would be returned
function NameOfTheFactoryTwo(){
   var factory = {
      getSomeService : function(){
          return new SomeService();
       }
    };
   return factory;
}

现在在控制器中使用以上两个:

 var factoryOne = NameOfTheFactoryOne() //since it returns a function
 factoryOne.someMethod();

 var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object
 factoryTwo.someMethod();

工厂特点:

  1. 此类服务遵循工厂设计模式。可以将工厂视为创建新对象或方法的中心位置。

  2. 这不仅产生单例,而且产生可定制的服务。

  3. .service()方法是始终提供相同类型服务的工厂,即单例。没有简单的方法可以配置它的行为。该.service()方法通常用作不需要任何配置的快捷方式。



0

您可以用这种类比来理解差异-考虑将返回某些值的普通函数与将使用new关键字实例化的构造函数之间的区别。因此创建工厂与创建可返回一些值(原始或原始)的普通函数相似。对象),而创建服务就像创建构造函数(OO类),我们可以使用new关键字创建实例。唯一需要注意的是,当我们使用Service方法创建服务时,它将使用AngularJS支持的依赖注入机制自动创建其实例。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.