Angular之Providers (Value, Factory, Service and Constant )

官方文档Providers

Each web application you build is composed of objects that collaborate to get stuff done.(每一个web应用都是由一些对象“组装”成的,这些对象共同合作,来完成特定的任务)These objects need to be instantiated and wired together for the app to work.(这些对象需要被实例化,然后“组装”在一起来使web应用能够工作) In Angular apps most of these objects are instantiated and wired together automatically(自动地) by the injector service.

The injector creates two types of objects, services and specialized objects.(两种对象:1 服务 和 2 特定的对象(控制器,指令,过滤器,动画))

Services are objects whose API is defined by the developer writing the service.

Specialized objects conform to a specific Angular framework API. These objects are one of controllers, directives, filters or animations.

The injector needs to know how to create these objects. You tell it by registering(通过注册) a "recipe" for creating your object with the injector. There are five recipe types.

The most verbose, but also the most comprehensive one is a Provider recipe. The remaining four recipe types — Value, Factory, Service and Constant — are just syntactic sugar(仅仅是依靠在provider上的语法糖) on top of a provider recipe.

Let‘s take a look at the different scenarios for creating and using services via various recipe types. We‘ll start with the simplest case possible where various places in your code need a shared string and we‘ll accomplish this via Value recipe.

Note: A Word on Modules

In order for the injector to know how to create and wire together all of these objects, it needs a registry(注册表) of "recipes". Each recipe has an identifier of the object and the description of how to create this object.

Each recipe belongs to an Angular module(属于一个Angular模块). An Angular module is a bag that holds one or more recipes. And since manually keeping track of module dependencies is no fun, a module can contain information about dependencies on other modules as well.

When an Angular application starts with a given application module, Angular creates a new instance of injector, which in turn creates a registry of recipes as a union of all recipes defined in the core "ng" module, application module and its dependencies(核心的“ng”模块,应用模块和它的依赖). The injector then consults the recipe registry when it needs to create an object for your application.(当需要为你的应用生成一个对象时,注册器就会去“咨询”注册表)

Value  Factory  Service  Provider

Value Recipe

Let‘s say that we want to have a very simple service called "clientId" that provides a string representing an authentication id used for some remote API. You would define it like this:

var myApp = angular.module(‘myApp‘, []);
myApp.value(‘clientId‘, ‘a12345654321x‘);

Notice how we created an Angular module called myApp, and specified that this module definition contains a "recipe" for constructing theclientId service, which is a simple string in this case.

And this is how you would display it via Angular‘s data-binding:

myApp.controller(‘DemoController‘, [‘clientId‘, function DemoController(clientId) {
  this.clientId = clientId;
}]);
<html ng-app="myApp">
  <body ng-controller="DemoController as demo">
    Client ID: {{demo.clientId}}
  </body>
</html>

In this example, we‘ve used the Value recipe to define the value to provide when DemoController asks for the service with id "clientId".

On to more complex examples!

Factory Recipe

The Value recipe is very simple to write, but lacks some important features we often need when creating services. Let‘s now look at the Value recipe‘s more powerful sibling, the Factory. The Factory recipe adds the following abilities:

  • ability to use other services (have dependencies)(可以使用依赖)
  • service initialization
  • delayed/lazy initialization

The Factory recipe constructs a new service using a function with zero or more arguments (these are dependencies on other services). The return value of this function is the service instance created by this recipe.

Note: All services in Angular are singletons(单列的). That means that the injector uses each recipe at most once to create the object. The injector then caches the reference(缓存起来) for all future needs.

Since a Factory is a more powerful version of the Value recipe, the same service can be constructed with it. Using our previous clientIdValue recipe example, we can rewrite it as a Factory recipe like this:

myApp.factory(‘clientId‘, function clientIdFactory() {
  return ‘a12345654321x‘;
});

But given that the token is just a string literal, sticking with the Value recipe is still more appropriate as it makes the code easier to follow.

Let‘s say, however, that we would also like to create a service that computes a token used for authentication against a remote API. This token will be called apiToken and will be computed based on the clientId value and a secret stored in the browser‘s local storage:

myApp.factory(‘apiToken‘, [‘clientId‘, function apiTokenFactory(clientId) {
  var encrypt = function(data1, data2) {
    // NSA-proof encryption algorithm:
    return (data1 + ‘:‘ + data2).toUpperCase();
  };

  var secret = window.localStorage.getItem(‘myApp.secret‘);
  var apiToken = encrypt(clientId, secret);

  return apiToken;
}]);

In the code above, we see how the apiToken service is defined via the Factory recipe that depends on the clientId service. The factory service then uses NSA-proof encryption to produce an authentication token.

Best Practice: name the factory functions as <serviceId>Factory (e.g., apiTokenFactory). While this naming convention is not required, it helps when navigating the codebase or looking at stack traces in the debugger.

Just like with the Value recipe, the Factory recipe can create a service of any type, whether it be a primitive, object literal, function, or even an instance of a custom type.

Service Recipe

JavaScript developers often use custom types to write object-oriented code. Let‘s explore how we could launch a unicorn into space via our unicornLauncher service which is an instance of a custom type:

function UnicornLauncher(apiToken) {

  this.launchedCount = 0;
  this.launch = function() {
    // Make a request to the remote API and include the apiToken
    ...
    this.launchedCount++;
  }
}

We are now ready to launch unicorns, but notice that UnicornLauncher depends on our apiToken. We can satisfy this dependency onapiToken using the Factory recipe:

myApp.factory(‘unicornLauncher‘, ["apiToken", function(apiToken) {
  return new UnicornLauncher(apiToken);
}]);

This is, however, exactly the use-case that the Service recipe is the most suitable for.

The Service recipe produces a service just like the Value or Factory recipes, but it does so by invoking a constructor with the new operator(通过调用一个构造函数). The constructor can take zero or more arguments, which represent dependencies needed by the instance of this type.

Note: Service recipes follow a design pattern called constructor injection.

Since we already have a constructor for our UnicornLauncher type, we can replace the Factory recipe above with a Service recipe like this:

myApp.service(‘unicornLauncher‘, ["apiToken", UnicornLauncher]);

Much simpler!

Note: Yes, we have called one of our service recipes ‘Service‘. We regret this and know that we‘ll be somehow punished for our misdeed. It‘s like we named one of our offspring ‘Child‘. Boy, that would mess with the teachers.

Provider Recipe

As already mentioned in the intro, the Provider recipe is the core recipe type(是核心的“服务”类型) and all the other recipe types are just syntactic sugar on top of it(其它的service类型都是以provider为基础的语法糖). It is the most verbose recipe with the most abilities, but for most services it‘s overkill.

The Provider recipe is syntactically defined as a custom type that implements a $get method. This method is a factory function just like the one we use in the Factory recipe. In fact, if you define a Factory recipe, an empty Provider type with the $get method set to your factory function is automatically created under the hood.

You should use the Provider recipe only when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applications.

Let‘s say that our unicornLauncher service is so awesome that many apps use it. By default the launcher shoots unicorns into space without any protective shielding. But on some planets the atmosphere is so thick that we must wrap every unicorn in tinfoil before sending it on its intergalactic trip, otherwise they would burn while passing through the atmosphere. It would then be great if we could configure the launcher to use the tinfoil shielding for each launch in apps that need it. We can make it configurable like so:

myApp.provider(‘unicornLauncher‘, function UnicornLauncherProvider() {
  var useTinfoilShielding = false;

  this.useTinfoilShielding = function(value) {
    useTinfoilShielding = !!value;
  };

  this.$get = ["apiToken", function unicornLauncherFactory(apiToken) {

    // let‘s assume that the UnicornLauncher constructor was also changed to
    // accept and use the useTinfoilShielding argument
    return new UnicornLauncher(apiToken, useTinfoilShielding);
  }];
});

To turn the tinfoil shielding on in our app, we need to create a config function via the module API and have the UnicornLauncherProvider injected into it:

myApp.config(["unicornLauncherProvider", function(unicornLauncherProvider) {
  unicornLauncherProvider.useTinfoilShielding(true);
}]);

Notice that the unicorn provider is injected into the config function. This injection is done by a provider injector which is different from the regular instance injector, in that it instantiates and wires (injects) all provider instances only.

During application bootstrap, before Angular goes off creating all services, it configures and instantiates all providers. We call this the configuration phase of the application life-cycle. During this phase, services aren‘t accessible because they haven‘t been created yet.

Once the configuration phase is over, interaction with providers is disallowed and the process of creating services starts. We call this part of the application life-cycle the run phase.

--------------------------------------------------------------------------------------

Confused about Service vs Factory

All angular services are singletons(angular中所有的服务都是单例的,只被实例化一次):

All Services are singletons; they get instantiated once per app. They can be of any type, whether it be a primitive, object literal, function, or even an instance of a custom type.

For me the revelation came when I realise that they all work the same way: by running something once, storing the value they get, and then cough up that same stored value when referenced through Dependency Injection.(实例化一次,依赖注入时注入的都是同一个服务)

Say we have:

app.factory(‘a‘, fn);
app.service(‘b‘, fn);
app.provider(‘c‘, fn);
The difference between the three is that:

a‘s stored value comes from running fn
b’s stored value comes from newing fn
c’s stored value comes from first getting an instance by newing fn, and then running a $get method of the instance
which means, there’s something like a cache object inside angular, whose value of each injection is only assigned once, when they‘ve been injected the first time, and where:

cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()
This is why we use this in services, and define a this.$get in providers(这就是为什么在service中使用this 在provider中使用this.$get方法).

---------------------------------------------------------------------------------------

AngularJS: Service vs provider vs factory

时间: 2024-06-22 00:33:34

Angular之Providers (Value, Factory, Service and Constant )的相关文章

Providers(Value, Factory, Service and Constant )

-------------------------------官方文档--------------------------------------------------------------------- Providers  AngularJS: Service vs provider vs factory Each web application you build is composed of objects that collaborate to get stuff done.(每一

AngularJS中几种Providers(Factory, Service, Provider)的区别

原文: http://blog.xebia.com/2013/09/01/differences-between-providers-in-angularjs/ 什么是Provider? AngularJS docs 是这样定义provider的: provider是一个对象, 它有一个$get()方法. injector 调用$get方法以此来创建一个service的实例. Provider还有一些其他的方法用来配置provider. AngularJS 使用 $provide 注册新的pro

AngularJS注册和使用服务和常量(provider、factory、service、constant、value)

1.   简介 AngularJS采用MVC架构,提供了服务的注册和以依赖注入方式使用服务的机制.服务是功能(方法)和数据(常量)的抽象,比如系统中关于用户信息相关的功能(头像.昵称.签名.生日.性别等信息的获取与修改)抽象后集中在一个对象中,那么这个对象就可以视为一个服务.服务可以通过angular.Module(常以var app = angular.module('my-app',[])方式获取)和$provider(以依赖注入方式获取)对象注册,常以依赖注入的方式使用使用. 每个服务有一

【备忘录】provider, factory, service, hello world example

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 sophistica

angularjs factory,service,provider 自定义服务的不同

angularjs框架学了有一段时间了,感觉很好用.可以把angularjs的app理解成php的class,controller是控制器,而内置服务和自定义服务就可以理解成models了.angularjs的内置服务多,例如:$scope,$rootScope,$http,$q,$resource,$routeProvider等等,下面来说一下怎么自定义服务 一,factory,service,provider自定义服务,services.js 'use strict'; /* Service

factory service provide自定义服务

1.factory factory , 就是你提供一个方法, 该方法返回一个对象的实例, 对于 AngularJS 的 factory 来说, 就是先定义一个对象, 给这个对象添加属性和方法, 然后返回这个对象, 例如: var app = angular.module('MyApp', []); app.factory('MyFactory', function() { // define result object of factory. var result = {}; // add so

angularjs 中 Factory,Service,Provider 之间的区别

本片文章是使用了 angularjs 中使用 service 在controller 之间 share 对象和数据 的code(http://jsfiddle.net/kn46u0uj/1/) 来进行演示 Factory,Service,Provider 之间的区别 1. Factory factory('dataService',function(){ return { golbal_sitename:"this is the shared value", sayHello:func

angular的service服务eg:value,constant,factory,service

app = angular.module("app",[]); app.value("realname","liyang");//可以改变 app.value("User",{name:"liyang" ,pwd:"123456"}) //可以直接绑定一个js对象 app.constant("baidu","www.baidu.com");//不可

AngularJS中的provider,factory,service方法

使用$provide中的provider方法定义服务 前面已经知道了module的定义为angular.module(name,[requires],configFn);configFn参数是配置服务的.ng供服务的过程涉及它的依赖注入机制.AngularJS是用$provider对象来实现自动依赖注入机制的.$provide.provider是一种定义服务的方法.注入机制通过调用provider的$get方法,把得到的对象作为参数进行相关的调用. <!DOCTYPE html> <ht