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


当前回答

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

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


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

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

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

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

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

其他回答

所有的好答案都已经有了。我想在服务和工厂方面再补充几点。以及服务/工厂之间的差异。你也可以有这样的问题:

我应该使用服务还是工厂?有什么不同?他们的行为是否相同?

让我们从服务和工厂之间的区别开始:

两者都是Singleton:每当Angular第一次发现它们作为依赖项时,它都会创建服务/工厂的单个实例。创建实例后,将永远使用同一实例。可用于对具有行为的对象进行建模:它们都可以有方法、内部状态变量等。尽管编写代码的方式会有所不同。

服务:

服务是一个构造函数,Angular将通过调用newyourServiceName()来实例化它。这意味着一些事情。

函数和实例变量将是它的财产。您不需要返回值。当Angular调用new yourServiceName()时,它将接收此对象以及您在其上放置的所有财产。

示例:

angular.service('MyService', function() {
  this.aServiceVariable = "Ved Prakash"
  this.aServiceMethod = function() {
    return //code
  };
});

当Angular将此MyService服务注入控制器时取决于它,该控制器将获得它可以调用的MyService上的函数,例如MyService.aServiceMethod()。

注意:

由于构造的服务是一个对象,因此当调用它们时,它内部的方法可以引用它:

angular.service('ScoreKeeper', function($http) {
  this.score = 0;

  this.getScore = function() {
    return this.score;
  };

  this.setScore = function(newScore) {
    this.score = newScore;
  };

  this.addOne = function() {
    this.score++;
  };
});

例如,如果您通过从服务器$http.get('/score').then(ScoreKeeper.setScore)获取分数来初始化分数,那么您可能会尝试在承诺链中调用ScoreKeeper。这样做的问题是,ScoreKeeer.setScore将在该绑定为空的情况下被调用,并且您会收到错误。更好的方法是$http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper))。无论您是否选择在服务方法中使用它,请注意如何调用它们。

从服务返回值:

由于JavaScript构造函数的工作方式,若从构造函数函数返回一个复杂值(即Object),调用者将获得该Object而不是该实例。

这意味着你基本上可以从下面复制粘贴工厂示例,用服务替换工厂,它会起作用:

angular.service('MyService', function($http) {
  var api = {};

  api.aServiceMethod= function() {
    return $http.get('/users');
  };
  return api;
});

因此,当Angular使用新的MyService()构造服务时,它将获得该api对象而不是MyService实例。

这是任何复杂值(对象、函数)的行为,但不是基本类型的行为。

工厂:

工厂是一个返回值的普通旧函数。返回值是注入到依赖于工厂的事物中的值。Angular中的一个典型工厂模式是返回一个具有函数作为财产的对象,如下所示:

angular.factory('MyFactory', function($http) {
  var api = {};

  api.aFactoryMethod= function() {
    return $http.get('/users');
  };

  return api;
});

工厂依赖项的注入值是工厂的返回值值,并且它不必是对象。这可能是一种功能

以上1和2个问题的答案:

大多数情况下,只要坚持使用工厂就可以了。他们的行为更容易理解。别无选择关于是否返回一个值,此外,没有错误如果你做错事,就会被介绍。当我谈论注射时,我仍然将其称为“服务”但它们是依赖关系。服务/工厂行为非常相似,有些人会说任何一个都很好。这有点正确,但我觉得遵循约翰·帕帕风格指南的建议,坚持工厂**

工厂:您实际在工厂内部创建对象并将其返回的工厂。service:您只有一个使用this关键字定义函数的标准函数的服务。provider:您定义了一个$get,它可以用来获取返回数据的对象。

了解AngularJS工厂、服务和提供商

所有这些都用于共享可重用的单例对象。它有助于在应用程序/各种组件/模块之间共享可重用代码。

来自文档服务/工厂:延迟实例化–Angular仅在应用程序组件依赖于服务/工厂时实例化它。单件–每个组件依赖于服务获取对单个实例的引用由服务工厂生成。

工厂

工厂是一个函数,您可以在创建对象之前操作/添加逻辑,然后返回新创建的对象。

app.factory('MyFactory', function() {
    var serviceObj = {};
    //creating an object with methods/functions or variables
    serviceObj.myFunction = function() {
        //TO DO:
    };
    //return that object
    return serviceObj;
});

用法

它可以只是像类一样的函数集合。因此,当您将其注入控制器/工厂/指令函数时,它可以在不同的控制器中实例化。每个应用程序只实例化一次。

服务

在查看服务时,只需考虑阵列原型。服务是一个使用“new”关键字实例化新对象的函数。您可以使用this关键字将财产和函数添加到服务对象。与工厂不同,它不返回任何内容(它返回包含方法/财产的对象)。

app.service('MyService', function() {
    //directly binding events to this context
    this.myServiceFunction = function() {
        //TO DO:
    };
});

用法

当您需要在整个应用程序中共享单个对象时,请使用它。例如,经过验证的用户详细信息、可共享的方法/数据、实用程序功能等。

供应商

提供程序用于创建可配置的服务对象。您可以通过config函数配置服务设置。它使用$get()函数返回一个值。$get函数在运行阶段以角度执行。

app.provider('configurableService', function() {
    var name = '';
    //this method can be be available at configuration time inside app.config.
    this.setName = function(newName) {
        name = newName;
    };
    this.$get = function() {
        var getName = function() {
             return name;
        };
        return {
            getName: getName //exposed object to where it gets injected.
        };
    };
});

用法

当您需要在服务对象可用之前为其提供模块化配置时,例如,假设您希望根据环境(如dev、stage或prod)设置API URL

注释只有提供程序在angular的配置阶段可用,而服务和工厂不是。

希望这能澄清您对工厂、服务和供应商的理解。

让我们以简单的方式讨论AngularJS中处理业务逻辑的三种方法:(灵感来自Yaakov的Coursera AngularJS课程)

服务:

语法:

应用程序.js

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

 ServiceExampleController.$inject = ['NameOfTheService'] //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;
     }     
}

索引html

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

服务特点:

懒惰实例化:如果它没有被注入,就永远不会被实例化。因此,要使用它,必须将其注入到模块中。Singleton:如果注入到多个模块,所有模块都只能访问一个特定的实例。这就是为什么在不同控制器之间共享数据非常方便的原因。

工厂

首先让我们看看语法:

应用.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();

工厂特点:

遵循工厂设计模式。工厂是生产新对象或功能的中心场所。不仅生成单例,还生成可定制的服务。.service()方法是一个工厂,它总是生成相同类型的服务,这是一个单例,没有任何简单的方法来配置它的行为。.service()方法通常用作不需要任何配置的快捷方式。

供应商

让我们先来看看语法:

angular.module('ProviderModule', [])
.controller('ProviderModuleController', ProviderModuleController)
.provider('ServiceProvider', ServiceProvider)
.config(Config); //optional

Config.$inject = ['ServiceProvider'];
function Config(ServiceProvider) {
  ServiceProvider.defaults.maxItems = 10; //some default value
}


ProviderModuleController.$inject = ['ServiceProvider'];
function ProviderModuleController(ServiceProvider) {
  //some methods
}

function ServiceProvider() {
  var provider = this;

  provider.defaults = {
    maxItems: 10
  };

  provider.$get = function () {
    var someList = new someListService(provider.defaults.maxItems);

    return someList;
  };
}

}

提供商的特点:

Provider是在Angular中创建服务的最灵活的方法。我们不仅可以创建一个可动态配置的工厂,而且在使用工厂时,通过提供程序方法,我们可以在整个应用程序启动时自定义配置工厂一次。然后,工厂可以在整个应用程序中使用自定义设置。换句话说,我们可以在应用程序启动之前配置此工厂。事实上,在angular文档中提到,当我们使用.service或.factory方法配置服务时,提供者方法实际上是在幕后执行的。$get是一个直接附加到提供程序实例的函数。该函数是工厂函数。换句话说,它就像我们用来提供给.factory方法的一样。在该函数中,我们创建自己的服务。这个$get属性是一个函数,它使提供者成为提供者。AngularJS希望提供程序具有$get属性,该属性的值是Angular将作为工厂函数处理的函数。但使整个提供程序设置非常特殊的是,我们可以在服务提供程序内部提供一些配置对象,这通常带有默认值,我们可以稍后在步骤中覆盖这些默认值,在该步骤中我们可以配置整个应用程序。

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

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


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

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

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

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

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