@yiranphp
2016-04-06T19:25:49.000000Z
字数 3303
阅读 3391
angular
在publishExternalAPI的阶段设置模块注册器(angular.module),源码比较长,并且使用了多层闭包。
setupModuleLoader源码以及化简版如下
function setupModuleLoader(window) {
var $injectorMinErr = minErr('$injector');
var ngMinErr = minErr('ng');
//该方法很有用,当obj有name属性的时候,作为getter来使用,否则作为setter来使用。
function ensure(obj, name, factory) {
return obj[name] || (obj[name] = factory());
}
var angular = ensure(window, 'angular', Object);
angular.$$minErr = angular.$$minErr || minErr;
// return angular.module = factory();
return ensure(angular, 'module', function() {
var modules = {};
return function module(name, requires, configFn) {
// 后续代码中会使用modules.hasOwnProperty方法,所以不能将模块的名字命名为hasOwnProperty
// angularJs的一个惯用的错误机制:断言,抛出错误,简称断言抛
var assertNotHasOwnProperty = function(name, context) {
if (name === 'hasOwnProperty') {
throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
}
};
assertNotHasOwnProperty(name, 'module');
// 同名模块重新注册
if (requires && modules.hasOwnProperty(name)) {
modules[name] = null;
}
// return modules[name] = factory();
return ensure(modules, name, function() {
if (!requires) {
throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
"the module name or forgot to load it. If registering a module ensure that you " +
"specify the dependencies as the second argument.", name);
}
var invokeQueue = [];
var configBlocks = [];
var runBlocks = [];
var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
var moduleInstance = {
// Private state
_invokeQueue: invokeQueue,
_configBlocks: configBlocks,
_runBlocks: runBlocks,
requires: requires,
name: name,
provider: invokeLater('$provide', 'provider'),
factory: invokeLater('$provide', 'factory'),
service: invokeLater('$provide', 'service'),
value: invokeLater('$provide', 'value'),
constant: invokeLater('$provide', 'constant', 'unshift'),
animation: invokeLater('$animateProvider', 'register'),
filter: invokeLater('$filterProvider', 'register'),
controller: invokeLater('$controllerProvider', 'register'),
directive: invokeLater('$compileProvider', 'directive'),
config: config,
run: function(block) {
runBlocks.push(block);
return this;
}
};
if (configFn) {
config(configFn);
}
return moduleInstance;
// queue默认为invokeQueue,返回的函数的作用就是将[provider, method, arguments]追加到queue数组中
function invokeLater(provider, method, insertMethod, queue) {
if (!queue) queue = invokeQueue;
return function() {
queue[insertMethod || 'push']([provider, method, arguments]);
return moduleInstance;
};
}
});
};
});
}
// 化简版如下
function setupModuleLoader(window) {
// ... ...
return angular.module = (function() {
var modules = {};
return function module(name, requires, configFn) {
return ensure(modules, name, function() {
// ... ...
var moduleInstance = {
// ... ...
};
return moduleInstance;
});
}
})();
}
总结一下:angular.module的使用
1. angular.module(name):getter方式调用,从modules中找注册过的模块,如果未注册过,直接抛出错误
2. angular.module(name, requires):setter方式调用,在modules中注册模块,如果已经注册过同名模块,先清空,后注册
3. angularJs应用中的所有模块都在modules中维护
var module1 = angular.module('mymodule1', []);
var module2 = angular.module('mymodule2', []);
var module3 = angular.module('plunker',['mymodule1', 'mymodule2']);
module3.controller("MainCtrl", ["$scope", function($scope) {
$scope.name = "yiranphp";
console.log('invoke')
}]);
module3.run(["$rootScope", function($rootScope) {
$rootScope.age = 20;
console.log('run');
}])
module3.config(["$httpProvider", function($httpProvider) {
console.log('config');
}]);
console.log(module3);
输出的先后顺序:
moduleInstance,config,run,invoke
可见:通过config、run、controller定义的函数不会立即执行,而是放进了moduleInstance的_invokeQueue、 _configBlocks、runBlocks中,并且是有先后顺序的,后续会详细解释