AngularJS中的服务、提供商和工厂之间有什么区别?


当前回答

对我来说,理解差异的最佳和最简单的方法是:

var service, factory;
service = factory = function(injection) {}

AngularJS如何实例化特定组件(简化):

// service
var angularService = new service(injection);

// factory
var angularFactory = factory(injection);

因此,对于服务,AngularJS组件是由服务声明函数表示的类的对象实例。对于工厂,它是从工厂声明函数返回的结果。工厂的行为可能与服务相同:

var factoryAsService = function(injection) {
  return new function(injection) {
    // Service content
  }
}

最简单的思考方式如下:

服务是一个单例对象实例。如果您想为代码提供单例对象,请使用服务。工厂是一个阶级。如果您想为代码提供自定义类,请使用工厂(无法使用服务完成,因为它们已经实例化)。

工厂“类”示例在周围的注释中提供,以及提供程序差异。

其他回答

我注意到了一些有趣的事情,当我和提供者一起玩的时候。

与服务和工厂相比,供应商对注射剂的可见性有所不同。如果您声明AngularJS“常量”(例如,myApp.constant('a','Robert');),您可以将其注入服务、工厂和提供商。

但是如果您声明一个AngularJS“value”(例如,myApp.value('b',{name:'Jones‘});),您可以将其注入服务和工厂,但不能注入提供程序创建函数。但是,您可以将其注入为提供者定义的$get函数中。AngularJS文档中提到了这一点,但很容易错过。您可以在%provide页面的value和constant方法部分找到它。

http://jsfiddle.net/R2Frv/1/

<div ng-app="MyAppName">
    <div ng-controller="MyCtrl">
        <p>from Service: {{servGreet}}</p>
        <p>from Provider: {{provGreet}}</p>
    </div>
</div>
<script>
    var myApp = angular.module('MyAppName', []);

    myApp.constant('a', 'Robert');
    myApp.value('b', {name: 'Jones'});

    myApp.service('greetService', function(a,b) {
        this.greeter = 'Hi there, ' + a + ' ' + b.name;
    });

    myApp.provider('greetProvider', function(a) {
        this.firstName = a;
        this.$get = function(b) {
            this.lastName = b.name;
            this.fullName = this.firstName + ' ' + this.lastName;
            return this;
        };
    });

    function MyCtrl($scope, greetService, greetProvider) {
        $scope.servGreet = greetService.greeter;
        $scope.provGreet = greetProvider.fullName;
    }
</script>

另外一个澄清是,工厂可以创建函数/原语,而服务不能。看看这个基于Epokk的jsFiddle:http://jsfiddle.net/skeller88/PxdSP/1351/.

工厂返回一个可以调用的函数:

myApp.factory('helloWorldFromFactory', function() {
  return function() {
    return "Hello, World!";
  };
});

工厂还可以返回具有可调用方法的对象:

myApp.factory('helloWorldFromFactory', function() {
  return {
    sayHello: function() {
      return "Hello, World!";
    }
  };
});

该服务返回一个具有可调用方法的对象:

myApp.service('helloWorldFromService', function() {
  this.sayHello = function() {
     return "Hello, World!";
  };
});

有关详细信息,请参阅我写的关于差异的帖子:http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/

句法糖是区别。只需要提供程序。或者换句话说,只有提供者才是真正的角度,所有其他提供者都是派生的(以减少代码)。还有一个简单的版本,叫做Value(),它只返回值,不返回计算或函数。偶数值是从提供程序派生的!

那么,为什么会出现这样的并发症,为什么我们不能只使用提供者而忘记其他一切呢?它应该可以帮助我们轻松编写代码,更好地进行沟通。开玩笑的回答是,它越复杂,框架的销售就越好。


可以返回value=value的提供程序一个可以实例化并返回=工厂(+值)提供程序可以实例化+做某事=服务(+工厂,+值)提供者=必须包含名为$get(+Factory,+Service,+Value)的属性

角注入为我们得出这一结论提供了第一个线索。

$injector用于检索提供者“不是服务,不是工厂,而是提供者”定义的对象实例。

更好的答案是:Angular服务由服务工厂创建。这些服务工厂是由服务提供程序创建的函数。服务提供程序是构造函数。实例化时,它们必须包含名为$get的属性,该属性保存服务工厂函数

因此,主供应器和注入器都将就位:)。当$get可以通过从IServiceProvider继承而在提供程序中实现时,Typescript就变得有趣了。

我对此事的澄清:

基本上,所有提到的类型(服务、工厂、提供者等)都只是创建和配置全局变量(当然,这些变量对整个应用程序是全局的),就像老式的全局变量一样。

虽然不建议使用全局变量,但这些全局变量的实际用途是通过将变量传递给相关控制器来提供依赖注入。

在为“全局变量”创建值时有许多复杂程度:

常数这定义了一个在整个应用程序中不应修改的实际常量,就像其他语言中的常量一样(JavaScript缺少的)。价值这是一个可修改的值或对象,它充当一些全局变量,甚至可以在创建其他服务或工厂时注入(请参阅有关这些的详细信息)。然而,它必须是一个“文字值”,这意味着必须写出实际值,并且不能使用任何计算或编程逻辑(换句话说,39或myText或{prop:“value”}可以,但2+2不行)。工厂一个更一般的值,可以立即计算。它的工作原理是将一个函数传递给AngularJS,其中包含计算值所需的逻辑,AngularJS执行该函数,并将返回值保存在命名变量中。请注意,可以返回对象(在这种情况下,它的功能类似于服务)或函数(将作为回调函数保存在变量中)。服务服务是工厂的更精简版本,只有当值是对象时才有效,它允许直接在函数中写入任何逻辑(就像它是构造函数一样),以及使用this关键字声明和访问对象财产。供应商与工厂的简化版本的服务不同,提供程序是一种更复杂但更灵活的初始化“全局”变量的方法,最大的灵活性是从app.config中设置值的选项。它的工作方式类似于使用服务和提供者的组合,方法是向提供者传递一个函数,该函数具有使用this关键字声明的财产,该关键字可以从app.config中使用。然后它需要有一个单独的$.get函数,该函数由AngularJS在通过app.config文件设置上述财产后执行,该$.get功能的行为与上述工厂相同,因为它的返回值用于初始化“全局”变量。

工厂

如果给AngularJS一个函数,AngularJS将在请求工厂时缓存并注入返回值。

例子:

app.factory('factory', function() {
    var name = '';
    // Return value **is** the object that will be injected
    return {
        name: name;
    }
})

用法:

app.controller('ctrl', function($scope, factory) {
     $scope.name = factory.name;
});

服务

如果给AngularJS一个函数,AngularJS将调用new来实例化它。AngularJS创建的实例将在请求服务时缓存并注入。由于new用于实例化服务,因此关键字this是有效的,并引用实例。

例子:

app.service('service', function() {
     var name = '';
     this.setName = function(newName) {
         name = newName;
     }
     this.getName = function() {
         return name;
     }
});

用法:

app.controller('ctrl', function($scope, service) {
   $scope.name = service.getName();
});

供应商

给AngularJS一个函数,AngularJS将调用它的$get函数。它是$get函数的返回值,将在请求服务时缓存并注入。

提供程序允许您在AngularJS调用$get方法获取可注入对象之前配置提供程序。

例子:

app.provider('provider', function() {
     var name = '';
     this.setName = function(newName) {
          name = newName;
     }
     this.$get = function() {
         return {
            name: name
         }
     }
})

用法(作为控制器中的注射剂)

app.controller('ctrl', function($scope, provider) {
    $scope.name = provider.name;
});

用法(在调用$get以创建可注射对象之前配置提供程序)

app.config(function(providerProvider) {
    providerProvider.setName('John');
});