angular.js dependency injection

 

Understanding Dependency Injection in AngularJS

Dependency injection in AngularJS is very useful and it is also the key to our ability to easily test components. In this article we will explain how the AngularJS dependency injection system works.

 

AngularJS provides a good dependency injection mechanism. The following 5 core components are used for dependency injection:

         service

         provider

         value

         factory

         constant

 

Provider service ($provide)

The $provide service is responsible for telling Angular how to create a new injectable: a service. Services are defined by something called a provider, and you can use $provide to create a provider. You need to define a provider using the provider method in $provide, and you can also get the $provide service by asking the service to be injected into an application's config function.

app.config(function($provide) {
  $provide.provider('greeting', function() {
this.$get = function() {
  return function(name) {
alert("Hello, " + name);
  };
};
  });
});  

 

In the above example we defined a new provider called greeting for a service; we could inject a variable called greeting into any injectable function (such as a controller) and Angular would call the provider's $get function to return an instance of this service. In the above example, the injected function is a function that takes a parameter called name and alerts a message based on this parameter. We can use it like this:

app.controller('MainController', function($scope, greeting) {
  $scope.onClick = function() {
greeting('Ford Prefect');
  };
});

  

Now comes the interesting thing. factory, service, and value are all shorthand for defining a provider, and they provide a way to define a provider without typing all the complicated code. For example, you can define a provider exactly like before with the following code:

app.config(function($provide) {
  $provide.factory('greeting', function() {
return function(name) {
  alert("Hello, " + name);
};
  });
});  

 This is very important, behind the scenes, AngularJS is actually calling the code that appeared earlier (that is, the version of $provide.provider). Literally, there is basically no difference between the two methods. The same goes for the value method - if we need the value returned from the $get function (that is, our factory function) to always be the same, we can use the value method to write less code. For example, if our greeting service always returns the same function, we can use value to define it:

app.config(function($provide) {
  $provide.value('greeting', function(name) {
alert("Hello, " + name);
  });
});  

 Again, the effect of the above two methods is exactly the same - just the amount of code is different

app.config(function($provide){...})  

 Since defining a new provider is so common, AngularJS exposes the provider method directly on the module object to reduce code typing:

var myMod = angular.module('myModule', []);

myMod.provider("greeting", ...);
myMod.factory("greeting", ...);
myMod.value("greeting", ...);  

 The above code app.config(...)is exactly the same as before.

In addition to the things mentioned above that can be injected, there is also a constant method. Basically, it is the same as the usage of value. We will discuss the differences between the two later.

To reinforce the previous learnings, all of the following code does the same thing:

myMod.provider('greeting', function() {
  this.$get = function() {
return function(name) {
  alert("Hello, " + name);
};
  };
});

myMod.factory('greeting', function() {
  return function(name) {
alert("Hello, " + name);
  };
});

myMod.value('greeting', function(name) {
  alert("Hello, " + name);
});  

Injector ($injector)

The injector is responsible for creating the injected instance from the service we created via $provide. As long as you write a parameter with injectability, you can see how the injector works. Every AngularJS application has a unique $injector, which is created when the application starts, and you can get it by injecting $injector into any injectable function ($injector knows how to inject itself!).

Once you have $injector, you can get an instance of any service that has been defined by calling the get function. E.g:

var greeting = $injector.get('greeting');
greeting('Ford Prefect');  

 注入器同样也负责将服务注入到函数中;例如,你可以魔法般的将服务注入到任何函数中,只要你使用了注入器的invoke方法:

var myFunction = function(greeting) {
  greeting('Ford Prefect');
};
$injector.invoke(myFunction);  

 如果注入器只是创建一个服务的实例一次的话,那么它也没什么了不起的。它的厉害之处在于,他能够通过服务名称缓存从一个provider中返回的任何东西,当你下一次再使用这个服务时,你将会得到同一个对象。

因此,你可以通过调用$injector.invike将服务注入到任何函数中也是合情合理的了。包括:

  • 控制器定义函数
  • 指令定义函数
  • 过滤器定义函数
  • provider中的$get方法(也就是factory函数)

由于constant和value总是返回一个静态值,它们不会通过注入器被调用,因此你不能在其中注入任何东西。

配置provider

你可能会感到困惑:既然factorry和value能够节省那么多的代码,为什么还有人要使用provider。答案是provider允许我们进行一些配置。在前面我们已经提到过当你通过provider(或者其他简写方法)创建一个服务时,你实际上创建了一个新的provider,它将定义你的服务如何被创建。我们没有提到的是,这些provider可以被注入到config函数中,你可以和它们进行一些交互。

首先,AngularJS分两个阶段运行你的应用 – config阶段和run阶段。config阶段是你设置任何的provider的阶段。它也是你设置任何的指令,控制器,过滤器以及其它东西的阶段。在run阶段,AngularJS会编译你的DOM并启动你的应用。

你可以在myMod.config和myMod.run中添加任何代码 – 这两个函数分别在两个阶段运行。正如我们看到的,这些函数都是可以被注入的 – 我们在第一个例子中注入了内建的$provide函数。然而,值得注意的是在config阶段,只有provider能被注入(只有两个例外是$provide和$injector)。

例如,下面的代码就是错误的写法:

myMod.config(function(greeting) {
  //不会运行 -- greeting是一个服务的实例
  //只有服务的provider能被注入到config中
});

  但是你可以通过下面的方法注入provider:

myMod.config(function(greetingProvider) {
  // 这下好了!
});  

 有一个例外:constant,由于它们不能被改变,因此它不能被注入到config中(这就是它和value之间的不同之处)。它们只能通过名字被获取。

无论何时你为一个服务定义了一个provider,这个provider的名字都是serviceProvider。在这里service是服务的名字。现在我们可以使用provider的力量来做一些更复杂的事情了!

myMod.provider('greeting', function() {
  var text = 'Hello, ';

  this.setText = function(value) {
     text = value;
  };

  this.$get = function() {
     return function(name) {
         alert(text + name);
     };
  };
});

myMod.config(function(greetingProvider) {
  greetingProvider.setText("Howdy there, ");
});

myMod.run(function(greeting) {
  greeting('Ford Prefect');
});

 现在我们在provider中拥有了一个叫做setText的函数,我们可以使用它来自定义我们alert的内容;我们可以再config中访问这个provider,调用setText方法并自定义我们的service。当我们最终运行我们的应用时,我们可以获取greeting服务,然后你会看到我们自定义的行为起作用了。

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326953418&siteId=291194637