翻译自Angular service or factory?(貌似要翻墙)
若觉得太长了,可直接跳到底部的总结。
在很多AngularJS的教程和文档中,作者时而使用service
factory
,但从来不解释
为什么。更别说其实你还能用
value
和
constant
了。
我们来看看在什么情况下你应该使用哪个。首先,我们也应该理解providers的工作方式:
provider
这是provieder
方法的源码:
function provider(name, provider_) {
if (isFunction(provider_) || isArray(provider_)) {
provider_ = providerInjector.instantiate(provider_);
}
if (!provider_.$get) {
throw Error('Provider ' + name + ' must define $get factory method.');
}
return providerCache[name + providerSuffix] = provider_;
}
name
是字符串. provider_
可以是这三种东西之一:
-
函数(function)
如果传入的是一个函数,那么这个函数会被 dependency injection调用,并返回一个有
$get
方法的对象 -
数组(array)
数组被视为使用Inline Annotation的函数, 它也必须返回一个有
$get
方法的对象。 -
对象(object)
如果传入的是个对象,那么它应该是有
$get
方法的对象。
无论provider
的第二个参数是什么,你最终都会个到一个拥有$get
方法的对象。以这段代码为例:
// You can run this
// Create a module
var hippo = angular.module('hippo', []);
// Register an object provider
hippo.provider('awesome', {
$get: function() {
return 'awesome data';
}
});
// Get the injector (this happens behind the scenes in angular apps)
var injector = angular.injector(['hippo', 'ng']);
// Call a function with dependency injection
injector.invoke(function(awesome) {
console.log('awesome == ' + awesome);
});
一旦你理解了provider,你就会发现factory
, service
, value
和constant
只是生成provider的快捷方式
factory
这是源代码:
function factory(name, factoryFn) {
return provider(name, { $get: factoryFn });
}
所以你可以简单的把一个名叫awesome
的provider写成这个样子:
hippo.factory('awesome', function() {
return 'awesome data';
})
service
这是源代码:
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
所以这可以让你构建一个factory,用它可以初始化一个“类(class)”,比如说:
var gandalf = angular.module('gandalf', []);
function Gandalf() {
this.color = 'grey';
}
Gandalf.prototype.comeBack = function() {
this.color = 'white';
}
gandalf.service('gandalfService', Gandalf);
var injector = angular.injector(['gandalf', 'ng']);
injector.invoke(function(gandalfService) {
console.log(gandalfService.color);
gandalfService.comeBack()
console.log(gandalfService.color);
});
以上的代码会生成一个Gandalf
(译注:即甘道夫,魔戒里的白胡子老头),但是请记住,使用同一个service返回的实例都是同一个实例(这是件好事)。
value
这是源代码:
function value(name, value) {
return factory(name, valueFn(value));
}
用value
可以让你把awesome
的缩短成这样:
hippo.value('awesome', 'awesome data');
constant
这是源代码:
function constant(name, value) {
providerCache[name] = value;
instanceCache[name] = value;
}
constant
和value
不同,constant
在config的时候是可达的(accessible),如下例:
var joe = angular.module('joe', []);
joe.constant('bobTheConstant', 'a value');
joe.value('samTheValue', 'a different value');
joe.config(function(bobTheConstant) {
console.log(bobTheConstant);
});
joe.config(function(samTheValue) {
console.log(samTheValue);
});
// This will fail with "Error: Unknown provider: samTheValue from joe"
var injector = angular.injector(['joe', 'ng']);
在Modules文档的Module Loading & Dependencies部分可以获得更多信息。
总结
如果你想像调用普通函数那样调用你的函数,用factory
,如果你想用new
操作符来实例化你的函数,那么使用service
。如果你不知道这其中的区别在那里,那就用factory
以下是AngularJS源代码中,每个函数(很棒的)注释文档:
-
factory
A short hand for configuring services if only
$get
method is required. -
service
A short hand for registering service of given class.
-
value
A short hand for configuring services if the
$get
method is a constant. -
constant
A constant value, but unlike {@link AUTO.$provide#value value} it can be injected into configuration function (other modules) and it is not interceptable by {@link AUTO.$provide#decorator decorator}.