@yiranphp
2016-04-06T11:25:49.000000Z
字数 3303
阅读 3694
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中,并且是有先后顺序的,后续会详细解释