Angularjs 源码分析-setupModuleLoader

setupModuleLoader源码结构

下面是setupModuleLoader的源码结构部分(省略掉的部门会在后面详细讲解)

function setupModuleLoader(window) {//省略...function ensure(obj, name, factory) {return obj[name] || (obj[name] = factory());}var angular = ensure(window, 'angular', Object);angular.$$minErr = angular.$$minErr || minErr;return ensure(angular, 'module', function() {var modules = {};return function module(name, requires, configFn) {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 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: invokeLaterAndSetModuleName('$provide', 'provider'),factory: invokeLaterAndSetModuleName('$provide', 'factory'),service: invokeLaterAndSetModuleName('$provide', 'service'),value: invokeLater('$provide', 'value'),constant: invokeLater('$provide', 'constant', 'unshift'),decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),config: config,run: function(block) {runBlocks.push(block);return this;}};if (configFn) {config(configFn);}return moduleInstance;function invokeLater(provider, method, insertMethod, queue) {//省略...}function invokeLaterAndSetModuleName(provider, method) {//省略...}});};});}

接下来,我们针对上述代码逐一解析

ensure

  function ensure(obj, name, factory) {return obj[name] || (obj[name] = factory());}

该函数实现了module的getter和setter功能,在整个setupModuleLoader中被广泛使用了

invokeLater 和 invokeLaterAndSetModuleName

function invokeLater(provider, method, insertMethod, queue) {if (!queue) queue = invokeQueue;return function() {queue[insertMethod || 'push']([provider, method, arguments]);return moduleInstance;};
}function invokeLaterAndSetModuleName(provider, method) {return function(recipeName, factoryFunction) {if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;invokeQueue.push([provider, method, arguments]);return moduleInstance;};
}

顾名思义就是延迟执行的意思,先把要执行的对象(provider),要执行的方法(method),以及执行参数(auguments)都保存到queue中,在后面的代码分析中我们会分析另外一个函数loadmodules,也就是在loadmodules才真正执行

函数最后返回moduleInstance可以实现链式调用

invokeLaterAndSetModuleName相比invokeLater,默认queue为invokeQueue,并且保存了module的名字在$$moduleName,通过源码我们总结出

module方法providermethodqueueinsertMethod
config$injectorinvokeconfigBlockspush
provider$providerproviderinvokeQueuepush
factory$providerfactoryinvokeQueuepush
service$providerserviceinvokeQueuepush
value$providervalueconfigBlockspush
constant$providerconstantconfigBlocksunshift
animation$animateProviderregisterinvokeQueuepush
filter$filterProviderregisterinvokeQueuepush
controller$controllerProviderregisterinvokeQueuepush
directive$compileProviderdirectiveinvokeQueuepush

setupModuleLoader私有变量

假设有一个module app,var app = angular.module('app',[...])
  • invokeQueue
    类型为数组,主要用来保存调用app.controller,app.service,app.directive…等方法的参数,具体方法见上表
    比如调用
app.controller('testCtrl',["\$rootScope",function(\$scope){...}])
invokeQueue就会增加一条记录
["$controllerProvider","register",['testCtrl',["\$rootScope",function(\$scope){...}]]]
  • configBlocks
    类型为数组,主要用来保存类似app.config(),app.value()
    给module配置信息,支持两种方式,一种就是上面的app.config,还有一种就是定义的时候,第三个参数就是配置函数,如下
var app = angular.module('app',[],['xxx',function(xxx){}])
invokeQueue和configBlocks在loadModules中都被同一个方法调用了一次,调用顺序不一样
  //省略if (isString(module)) {moduleFn = angularModule(module);runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);runInvokeQueue(moduleFn._invokeQueue);runInvokeQueue(moduleFn._configBlocks);//省略
  • runBlocks
    类型为数组,主要用来保存app.run()中run里面的内容


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部