对服务与工厂感到困惑

Jvd*_*erg 616 angularjs

据我了解,当在工厂内部时,我返回一个被注入控制器的对象.在服务内部时,我正在处理使用的对象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;
});
Run Code Online (Sandbox Code Playgroud)

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

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

mat*_*4pl 600

所有角度服务都是单身人士:

文档(请参阅单项服务):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 + "!";
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

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

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

  • 间接的官方文件[原文如此!不明白]暗示即使你用工厂定义服务,它只创建一次.换句话说,根据参考(注入点)再次创建它 - 无论你怎么称呼它.两种方式都会导致每个注射器的单例实例. (31认同)
  • 我的印象是,服务是通过获取对它的引用而使用的单例.而且工厂是一个每次都返回一个新对象的单身人士.也就是说,一项服务会给你一辆"汽车",你项目中的所有东西都会使用这辆车.虽然每次调用工厂时工厂都会给你一辆新车.一个是返回单身的单身人士,一个是返回一个物体的单身人士.谁能解释一下?将所有东西称为单身并没有帮助,因为它可以引用多个东西. (14认同)
  • 另请参阅http://stackoverflow.com/questions/15666048/angular-js-service-vs-provide-vs-factory/15666049#15666049,其中讨论了服务,工厂和提供之间的差异. (13认同)
  • @nfiniteloop,检查第3574行附近的源代码.工厂是提供者的$ get方法,服务使用在提供的函数上调用$ injector.instantiate的方法生成工厂,然后调用new.([见文件](http://docs.angularjs.org/api/AUTO.$injector)) (5认同)
  • 你说"服务只是一个用'新'来调用的构造函数",但我认为这是误导性的.我不认为它是在幕后调用的,我认为开发人员负责在其上调用`new`. (3认同)
  • 工厂不一定需要返回一个对象。它可以返回任何你想要的。服务返回函数实例。 (2认同)

Luc*_*cia 380

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

说我们有:

app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);
Run Code Online (Sandbox Code Playgroud)

三者之间的区别在于:

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

这意味着,有一些类似于角度内的缓存对象,每次注入的值只分配一次,当它们第一次注入时,其中:

cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()
Run Code Online (Sandbox Code Playgroud)

这就是我们this在服务中使用并定义this.$get提供者的原因.

希望这可以帮助.

  • 最后,一个理智的解释.Angular很疯狂,非常糟糕,很痛. (54认同)
  • 这应该是公认的答案,因为它实际上回答了为什么工厂,服务和提供者返回单例值的问题.其他答案解释了工厂,服务和提供商之间的差异,但从未涉及单身方面. (8认同)
  • 我喜欢这个...当我从其他博主那里读到一千行句子时......我只能理解工厂.但是我读到了这个...我明白所有3. (3认同)
  • 所以你在使用提供者时必须提供$ get的实现? (2认同)

Epo*_*okK 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()];
}?
Run Code Online (Sandbox Code Playgroud)


Jus*_*cha 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 });
  };
}); 
Run Code Online (Sandbox Code Playgroud)

所以你可以在一个使用MyObjectWithParam的控制器中做到这一点:

var obj = new MyObjectWithParam("hello"),
Run Code Online (Sandbox Code Playgroud)

请参阅此处的完整示例:http:
//plnkr.co/edit/GKnhIN?p = preview

在这里讨论了google网页:http://groups.google.com/forum/#! msg/angular / 56sdORWEoqg /
b8hdPskxZXsJ

  • 我认为因为**服务是单身**.我在这里构建的**基本上是一个新的类**.因此,你可以拥有像汽车服务工厂那样的东西,然后制造新车('宝马')和新车('福特'),他们不会共享相同的变量和一切. (5认同)
  • 如果你可以使用`.service`,你为什么要这样做呢? (4认同)
  • 是的,Angular存在一个缩小的符号.它应该是这样的:'App.factory( 'MyObjectWithParam',[ '$喷油器',函数($注射器){返回功能(名称){$回报injector.instantiate(MyObjectWithParam,{名称:名});} ;}]); `在这里阅读更多相关信息:https://docs.angularjs.org/tutorial/step_05 (2认同)

小智 51

以下是主要差异:

服务

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

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

用法:通过简单地向注入的函数引用附加()来共享对调用有用的实用程序函数非常有用.也可以与injectedArg.call( this )或类似的运行.

工厂

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

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

用法:用于返回一个'class'函数,然后可以用来创建实例.

还要检查AngularJS文档和stackoverflow上关于服务与工厂混淆的类似问题.

这是使用服务和工厂的示例.阅读更多关于AngularJS服务与工厂的信息.

  • 这对我来说很有意义.他工厂返回创建新对象的蓝图. (6认同)
  • 其中一个更清晰的描述! (4认同)

Sut*_*bey 27

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

工厂适用于编写代码的开发人员,这些代码对于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);
    }]);
  }
Run Code Online (Sandbox Code Playgroud)


bin*_*les 25

非常简单:

.service - 注册函数将作为构造函数调用(又名'newed')

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

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

  • 是.让我们不要让事情变得比实际更复杂 (6认同)

Lui*_*rez 20

所有提供商的工作方式相同.不同的方法service,factory,provider只是让你完成同样的事情在更少的代码.

PS还有valueconstant.

从链开始到provider结束的每个特殊情况value都有一个额外的限制.因此,要在它们之间做出决定,你必须问问自己哪些让你用更少的代码完成你想要的东西.

这是一张图片,告诉你我的意思:

在此输入图像描述

你可以在博客文章中找到细分和参考指南,我得到了这张图片:

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


Rud*_*lah 13

以下是服务与工厂的更多示例,这些示例可能有助于了解它们之间的差异.基本上,一个服务有"新..."调用它,它已经被实例化.工厂不会自动实例化.

基本的例子

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

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

angular.service('Hello', function () {
  this.sayHello = function () { /* ... */ };
});
Run Code Online (Sandbox Code Playgroud)

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

angular.factory('ClassFactory', function () {
  return {
    sayHello: function () { /* ... */ }
  };
});
Run Code Online (Sandbox Code Playgroud)

返回一个值

返回数字列表的工厂:

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

console.log(NumberListFactory);
Run Code Online (Sandbox Code Playgroud)

返回数字列表的服务:

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

console.log(NumberLister.numbers);
Run Code Online (Sandbox Code Playgroud)

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

高级示例

使用工厂的"类"变量

在这个例子中,我们定义了一个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;
    };
  }

})
Run Code Online (Sandbox Code Playgroud)

我们使用它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());
Run Code Online (Sandbox Code Playgroud)

此代码的输出是:

people 0
people 1
counters 1
places 0
counters 2
counters 2
Run Code Online (Sandbox Code Playgroud)


Shi*_*ala 13

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

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

app.service("Logger", Logger); // Injects a global object
Run Code Online (Sandbox Code Playgroud)

使用"工厂"定义DI时,它不会创建实例.它只是传递方法,后来消费者在内部必须为工厂调用对象实例.

app.factory("Customerfactory", CreateCustomer);
Run Code Online (Sandbox Code Playgroud)

下面是一个简单的图像,直观地显示了"服务"的DI过程与"工厂"的不同之处.

在此输入图像描述

当我们想要根据场景创建不同类型的对象时,应该使用工厂.例如,取决于我们想要创建简单"客户"对象的场景,或者具有"地址"对象的"客户"或具有"电话"对象的"客户".以下是本段的详细说明

应该使用服务当我们注入实用程序或共享函数时,如Utility,Logger,Error handler等.


Pre*_*raj 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();

});
Run Code Online (Sandbox Code Playgroud)

工厂风格:( 更多涉及但更复杂)返回函数的返回值:在java中实例化一个对象,如new Object().

工厂是一个创造价值的功能.当服务,控制器等需要从工厂注入的值时,工厂按需创建值.一旦创建,该值将重用于需要注入的所有服务,控制器等.

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);

});
Run Code Online (Sandbox Code Playgroud)

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

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();
    }

});
Run Code Online (Sandbox Code Playgroud)

src jenkov

<!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>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

的jsfiddle