如果你正在寻找不同,可能是因为你正在找出哪一个对于你才是合适的。或者是因为你已经遇到了它们三个,并且因为它们看起来相似而判断不同处。
如果你认为它们是相似的 - 你就答对了。它们是非常相似的。事实上,他们都是一样的本质。
他们都是provider。factory和service仅仅是provider的特殊实例,但是你能完成你想用provider做的所有事情。比如:
Provider
我们将创建一个provider,返回一个值并且简单的展示这个值。
<body ng-app="MyModule">
<div ng-controller="MyController"></div>
</body>
var mod = angular.module("MyModule", []);
mod.provider("myProvider", function() {
this.$get = function() {
return "My Value";
};
});
mod.controller("MyController", function(myProvider) {
console.log("MyController - myProvider: " + myProvider);
});
输出:
MyController - myProvider: My Value
动态的例子可以看这里:JS Fiddle
这里,如此一个“provider”意味着让你“provider”一个值。这个值可以是任何内容。在这种情况下,它是一个值为“My Value”的字符串,但也可以是方法或者一个对象。
注意在接下来的代码示例中,我将排除<body>标签和<mod>定义,为了保持代码片段简短扼要。
Angular仅仅得到了一次值
注意,Angular仅仅“gets”一次值,无论provider被注入多少次。这意味着它曾仅仅调用$get()一次,存储在它提供的值中,并且每次给你相同的存储值。
为了让你明白我说的,我将创建另一个controller然后带着输出状态再次注入到provider中,以至于你能看到发生了什么。
<div ng-controller="MyController"></div>
<div ng-controller="MyController2"></div>
mod.provider("myProvider", function() {
this.$get = function() {
console.log("MyProviderFunction.$get() called."); // ADDED this line
return "My Value";
};
});
mod.controller("MyController", function(myProvider) {
console.log("MyController - myProvider: " + myProvider);
});
mod.controller("MyController2", function(myProvider) { // ADDED this controller
console.log("MyController2 - myProvider: " + myProvider);
});
输出:
MyProviderFunction.$get() called.
MyController - myProvider: My Value
MyController2 - myProvider: My Value
在JS Fiddle中打开
正如你能看到$get()方法刚只被调用了一次。
注意,我们为provider写了一部分代码的目的仅仅是证明创建了一个$get()方法。为什么不代替给angular一个方法而是定义另一个方法(注:这里的意思是为什么要多定义一个$get方法),为什么不代替它,仅仅是给它我们想要直接运行的方法?对,这就是angular的factory。
Factory
有了factory你就可以提供方法体给$get方法,angular做剩下的事情。下面是新的代码,你将看到结果会相同。
mod.factory("myProvider", function() { // CHANGED “provider" to “factory"
console.log("Factory function called.");
return "My Value";
});
mod.controller("MyController", function(myProvider) {
console.log("MyController - myProvider: " + myProvider);
});
mod.controller("MyController2", function(myProvider) {
console.log("MyController2 - myProvider: " + myProvider);
});
输出
Factory function called.
MyController - myProvider: My Value
MyController2 - myProvider: My Value
在JS Fiddle中打开
现在你可能想知道为什么你曾使用provider,但是factory可以用更少的代码完成同样的功能。有几个原因我稍后深入的说,现在我想继续说主题。
目前为止,我们已经返回了一个简单的字符串值,但是在实践中我们可能更多次想返回的是一个对象。那么这不会改变之前的例子太多代码,我们就能很容易的把返回字符串变成一个对象。
例如,让我们返回一个叫做getValue()的对象。现在有很多方法你可以在JavaScript中创建一个对象,我们将使用“构造对象”的方式创建一个方法,方法中用属性和方法填充一个对象,然后用new关键字实例化它。
function MyObject() { // ADDED our object constructor
this.getValue = function() {
return "My Value";
};
}
mod.factory("myProvider", function() {
console.log("Factory function called.");
return new MyObject(); // CREATE an instance of our object
});
mod.controller("MyController", function(myProvider) {
console.log("MyController - myProvider: " + myProvider.getValue()); // CHANGED to call getValue()
});
mod.controller("MyController2", function(myProvider) {
console.log("MyController2 - myProvider: " + myProvider.getValue()); // CHANGED to call getValue()
});
输出结果:
Factory function called.
MyController - myProvider: My Value
MyController2 - myProvider: My Value
在JS Fiddle中打开
现在,我想对这个做一个小的调整,因为它将很好地引导我们进入下一个概念。在我们的例子中,我们创建了“构造对象”方法MyObject,但是由于我们只实例化在一个地方,我们也可以使用匿名函数来代替。
这是很小的改动,原代码:
function MyObject() {
this.getValue = function() {
return "My Value";
};
}
mod.factory("myProvider", function() {
console.log("Factory function called.");
return new MyObject();
});
改成:
mod.factory("myProvider", function() {
console.log("Factory function called.");
return new function() { // INLINED our object constructor
this.getValue = function() {
return "My Value";
};
};
});
mod.factory("myProvider", function() {
console.log("Factory function called.");
return new function() { // INLINED our object constructor
this.getValue = function() {
return "My Value";
};
};
});
mod.controller("MyController", function(myProvider) {
console.log("MyController - myProvider: " + myProvider.getValue());
});
mod.controller("MyController2", function(myProvider) {
console.log("MyController2 - myProvider: " + myProvider.getValue());
});
在JS Fiddle中打开
现在既然我们整个factory由一个单独的对象组成,如果我们只是给angular构造对象方法,代替必须写看起来时髦的factory岂不是更好。很好你很幸运,这确实是service所做的。
service
下面是相同的代码,用service代替factory
mod.service("myProvider", function() { // CHANGED "factory" to "service"
// NOTE that the only function being passed is the object constructor from before
this.getValue = function() {
return "My Value";
};
});
mod.controller("MyController", function(myProvider) {
console.log("MyController - myProvider: " + myProvider.getValue());
});
mod.controller("MyController2", function(myProvider) {
console.log("MyController2 - myProvider: " + myProvider.getValue());
});
输出: MyController - myProvider: My Value MyController2 - myProvider: My Value
在JS Fiddle中打开
Provider VS Factory VS Service
正如概要,provider,factory和service都是provider。factory是provider的一个特例,在provider中当所有你需要的内容就是$get()。它允许你用少量的代码写。service是factory的一个特例,当你想返回一个新的对象,同样可以少写代码。
该用哪个呢?
答案是用你最熟悉的、能完成目标的版本。举个例子,你正返回一个现有的对象,这个对象被定义在其他需要构造参数的地方。你不能传递参数给service,因此你可以用factory代替它。
mod.factory("myProvider", function() {
console.log("Factory function called.");
return new SomeMessageBoxClass("custom argument");
});
provider和factory之间一个主要的、紧要的因素是你是否能够配置这个对象,在它产生之前配置它。你可以通过调用module.config(),得到一个实例给provider自己(代替通过provider返回对象)。当你要注入的时候,你可以通过在provider名字的末尾添加“provider”。
举个例子:
mod.provider("myProvider", function() {
this.value = "My Value";
this.setValue = function(newValue) {
this.value = newValue;
};
this.$get = function() {
return this.value;
};
});
mod.controller("MyController", function(myProvider) {
console.log("MyController - myProvider: " + myProvider);
});
mod.config(function(myProviderProvider) { // ADDED config section
// Note the extra "Provider" suffix
myProviderProvider.setValue("New Value");
});
这包括使用三个provider:provider,factory和service。还有一个provider没提到的,就是另一个特殊的例子——value。
如果你记得当我们第一次介绍factory时,我们给的简单的返回字符串的例子。代码如下:
mod.factory("myProvider", function() {
return "My Value";
});
我们当时已经使用了value,我们再一次用了少量的代码完成它。代码如下:
mod.value("myProvider", "My Value");
该用哪个呢?想必当你想基于其他数据计算值的时候使用factory,比如数据来自另一个value或外部代码。再又或者,当你想计算值仅仅是当它第一次被请求的时候。代码如下:
// Example where factory depends on a "value" provider
mod.value("multiple", 3);
mod.factory("value", function(multiple) {
return 10 * multiple;
});
// Example where factory depends on external data
mod.factory("value", function(multiple) {
var multiple = getDateFromExternalPage();
return 10 * multiple;
});
是不是意味着value是另一种provider?好吧,我撒谎了,这是另一个和value相似但是又有两处不同的provider,这就是constant。
value和constant之间的不同是当一个值指定为常量使用通常是在配置阶段。你可能还记得我之前提到的,provider使用在配置阶段,但service和factory不可以。
同样是value和constant。constant可以使用在配置阶段,而value不可以。另一个区别是,顾名思义,你不能改变一个常量的值。它保存第一次赋值,如果你试图去赋不同的值会不起作用。例如:
mod.value("myValue", "First Assignment");
mod.value("myValue", "Second Assignment");
mod.constant("myConstant", "First Assignment");
mod.constant("myConstant", "Second Assignment");
mod.controller("MyController", function(myValue, myConstant) {
console.log("myValue: " + myValue);
console.log("myConstant: " + myConstant);
});
输出:
myValue: Second Assignment
myConstant: First Assignment
这是是使用说明:
value | You are providing a simple literal value. | mod.value("myValue", 10); |
constant | You need to be able access that value during the configuration phase. (using.config() ) | mod.constant("myValue", 10); mod.config(function(myValue) { console.log(myValue); }); |
factory | The value you are providing needs to be calculated based on other data. | mod.constant("myValue", 10); mod.config(function(myValue) { console.log(myValue); }); |
service | You are returning an object with methods. | mod.service("myService", function() { var name = "Bob"; this.setName = function(newName) { this.name = newName; }; this.getName = function() { return this.name; } }); |
provider | You want to be able to configure, during the config phase, the object that is going to be created before it’s created. | mod.provider("greeter", function() { var name; this.setName = function(newName) { name = newName; }; this.$get = function() { return new function() { this.sayHi = function() { console.log("Hi " + name; }; }; }; }); mod.config(function(greeterProvider) { greeterProvider.setName(“John"); }); |
为了指出重点,这里最后用图片来说明provider,factory,service和value。
原文地址:
http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/