本文结合一些资料,谈谈AngularJS的依赖注入机制。主要参考资料有:
1. AngularJS官方文档:https://docs.angularjs.org/guide/di
2. Github文章:https://github.com/angular/angular.js/wiki/Understanding-Dependency-Injection
3. 专著:Pro AngularJS
4. AngularJS 源代码
一、关于依赖注入
依赖注入式AngularJS的重要特性之一,有关概念和定义参考维基百科。依赖注入简化了Angular解析模块/组件之间依赖的过程。通常一个组件要获得它的依赖,有三种方式:
var injector = angular.injector(['ng', 'myApp']);
return {
invoke: invoke,
instantiate: instantiate,
get: getService,
annotate: createInjector.$$annotate,
has: function(name) {
return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
}
};
其中前三个方法很重要,例如可以通过get方法获得一个需要注入的组件:
var comp = injector.get('component');
在Angular中,依赖注入可谓无孔不入。通常在两种场景(函数)下会使用到依赖注入:
myApp.controller('smallCatCtrl', ['$scope', function($scope){
$scope.sayCat = function(){
alert('I Love Circle!');
}
}]);
var MyController = function($scope, myService) {
// ...
}
MyController.$inject = ['$scope', 'myService'];
myApp.controller('MyController', MyController);
myApp.controller('smallCatCtrl', function($scope){
$scope.sayCat = function(){
alert('I Love Circle!');
}
});
var myFunction = function(hello) {
hello('My Cat');
};
$injector.invoke(myFunction);
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
function bootstrapApply(scope, element, compile, injector) {
scope.$apply(function() {
element.data('$injector', injector);
compile(element)(scope);
});
}]
);
myApp.config(function($provide) {
$provide.provider('sayHello', function() {
this.$get = function() {
return function(name) {
alert("Hello, cat " + name);
};
};
});
});
myApp.config(function($provide) {
$provide.factory('sayCat', function() {
return function(name) {
alert("Hello, Cat" + name);
};
});
});
myMod.factory("sayHello", ...);
myMod.service("sayHello", ...);
myMod.value("Cat", ...);
下面说说config/run方法。Angular在加载模块时经过两个阶段:config和run。传入config函数的方法会在当前模块加载时执行;传入run函数的方法会在所有模块加载结束后执行。因此,在config阶段即可配置多个provider,但是在config阶段,只有provider可以注入,因此自定义的service无法注入到config中。这也好理解,因为config阶段是对service进行配置的而不是使用service本身。在前面的代码中,$provide service本身就是一个provider(对于Angular应用来讲相当于一个'元provider'),在模块加载时会调用$provide的provider方法定义一个新的provider。再看一个具体的例子:
define(['angular'], function(angular){
return angular.module('myCat', [])
.provider('hello', function() {
var firstName = '';
this.makeName = function(first){
firstName = first;
}
this.$get = function() {
return function(name) {
alert("Hello, " + firstName + ' ' + name);
};
};
})
.config(function(helloProvider){
helloProvider.makeName('Circle');
})
.controller('catCtrl', [
'$scope',
'$q',
'hello',
function($scope, $defer, hello){
$scope.catName = "";
$scope.sayHello = function(){
hello('Jiang');//output 'Hello, Circle Jiang'
};
}]
);
});