本系列为AngularJS v1.3.20版本
我们知道在angluar在运行过程中, module和injection是它的基本组织架构。 因此做我们不妨以此处作为入口进行分析。
一个简单的示例如下
通过angular.module模块创建一个module对象, 在该对象上设置一个常量name, 一个服务info。
通过injector创建一个注射器, 使用get获取到module上注册的服务。
function test1() {
const module = window.angular.module('myModule', []);
module.constant('name', 'ali')
module.provider('info', {
$get: function (name) {
return {
name: name + Date.now(),
age: 18
}
}
});
const injector = angular.injector(['myModule'])
console.log(injector.get('info'))
}
setupMouleLoader
在上述示例中我们发现模块创建方法是挂载到angular上的, 所以angular.module('myModule', [])
调用之前会有一系列的初始化工作。
而setupMouleLoader即是用来创建一个模块加载器.
一下代码主要功能如下
- 创建angular对象,且在该对象上挂载用于创建模块的module方法
- 通过module方法创建moduleInstance实例, 该实例上挂载有provider、factory、service、constant等方法。
- 有代码可知invokeLater是一个延迟方法, 也就是说调用provider或者constant方法并不会将对应的服务和常量挂载到module上,
而是要等到loadModules
阶段
function setupModuleLoader(window) {
var $injectorMinErr = minErr('$injector');
var ngMinErr = minErr('ng');
function ensure(obj, name, factory) {
return obj[name] || (obj[name] = factory());
}
// 1. 创建一个angluar对象
var angular = ensure(window, 'angular', Object);
// We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
angular.$$minErr = angular.$$minErr || minErr;
return ensure(angular, 'module', function() {
/** @type {Object.<string, angular.Module>} */
var modules = {};
// 2, 创建模块调用方法
return function module(name, requires, configFn) {
return ensure(modules, name, function() {
/** @type {!Array.<Array.<*>>} */
var invokeQueue = [];
/** @type {!Array.<Function>} */
var configBlocks = [];
/** @type {!Array.<Function>} */
var runBlocks = [];
var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
/** @type {angular.Module} */
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'),
...
run: function(block) {
runBlocks.push(block);
return this;
}
};
if (configFn) {
config(configFn);
}
return moduleInstance;
// 注册服务延迟执行,
function invokeLater(provider, method, insertMethod, queue) {
if (!queue) queue = invokeQueue;
return function() {
queue[insertMethod || 'push']([provider, method, arguments]);
return moduleInstance;
};
}
});
};
});
}
createInjector
该方法用来创建注射器,返回一个injector实例
- 使用providerCache、instanceCache进行缓存设置。
- providerInjector是一个injector实例, providerCache用来存储原始的服务对象, 在loadModules阶段将服务进行缓存。
- instanceInjector也是一个injector实例对象,instanceCache用来存储服务
$get
结果对象 。providerInjector是存在于闭包内部的私有变量, 而instanceInjector则是return到外部的实例方法。
在AngularJS如果我们需要提供依赖注入服务时,会先在instanceCache查询是否存在该服务,如果不存在则转交给providerInjector进行查询(惰性加载的思想: 第一次访问某个服务时instanceCache并不存在, 这时候会从providerInjector中获取,并通过invoke方法触发$get调用返回调用结果)
function createInjector(modulesToLoad, strictDi) {
strictDi = (strictDi === true);
var INSTANTIATING = {},
providerSuffix = 'Provider',
path = [],
loadedModules = new HashMap([], true),
providerCache = {
$provide: {
...
}
},
providerInjector = (providerCache.$injector =
createInternalInjector(providerCache, function(serviceName, caller) {
if (angular.isString(caller)) {
path.push(caller);
}
throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
})),
instanceCache = {},
instanceInjector = (instanceCache.$injector =
createInternalInjector(instanceCache, function(serviceName, caller) {
// 如果该injector实例中不存在则去providerInjector中获取, 执行$get返回值作为依赖服务, 这也是在创建provider的时候需要$get的原因
var provider = providerInjector.get(serviceName + providerSuffix, caller);
return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
}));
forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
return instanceInjector;
////////////////////////////////////
// $provider
////////////////////////////////////
...
function provider(name, provider_) {
assertNotHasOwnProperty(name, 'service');
if (isFunction(provider_) || isArray(provider_)) {
provider_ = providerInjector.instantiate(provider_);
}
if (!provider_.$get) {
throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
}
return providerCache[name + providerSuffix] = provider_;
}
...
function constant(name, value) {
assertNotHasOwnProperty(name, 'constant');
providerCache[name] = value;
instanceCache[name] = value;
}
...
}
loadModules
该方法主要功能:遍历模块对象, 对之前存储在_invokeQueue中的待挂载的服务依次存储在providerCache缓存中。
function loadModules(modulesToLoad) {
var runBlocks = [], moduleFn;
forEach(modulesToLoad, function(module) {
if (loadedModules.get(module)) return;
loadedModules.put(module, true);
function runInvokeQueue(queue) {
var i, ii;
for (i = 0, ii = queue.length; i < ii; i++) {
var invokeArgs = queue[i],
provider = providerInjector.get(invokeArgs[0]);
provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
}
}
try {
if (isString(module)) {
moduleFn = angularModule(module);
runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
runInvokeQueue(moduleFn._invokeQueue);
runInvokeQueue(moduleFn._configBlocks);
} else if (isFunction(module)) {
runBlocks.push(providerInjector.invoke(module));
} else if (isArray(module)) {
runBlocks.push(providerInjector.invoke(module));
} else {
assertArgFn(module, 'module');
}
} catch (e) {
...
}
});
return runBlocks;
}
createInternalInjector
该方法的功能为
- 一个getService方法用来获取服务
- 一个invoke方法用来执行原服务的
$get
方法,返回真正的服务对象 - 一个instantiate方法用来实例化一个服务
- 最终返回injector实例对象。
////////////////////////////////////
// internal Injector
////////////////////////////////////
function createInternalInjector(cache, factory) {
function getService(serviceName, caller) {
if (cache.hasOwnProperty(serviceName)) {
if (cache[serviceName] === INSTANTIATING) {
throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
serviceName + ' <- ' + path.join(' <- '));
}
return cache[serviceName];
} else {
try {
path.unshift(serviceName);
cache[serviceName] = INSTANTIATING;
return cache[serviceName] = factory(serviceName, caller);
} catch (err) {
if (cache[serviceName] === INSTANTIATING) {
delete cache[serviceName];
}
throw err;
} finally {
path.shift();
}
}
}
function invoke(fn, self, locals, serviceName) {
if (typeof locals === 'string') {
serviceName = locals;
locals = null;
}
var args = [],
$inject = createInjector.$$annotate(fn, strictDi, serviceName),
length, i,
key;
...
// http://jsperf.com/angularjs-invoke-apply-vs-switch
// #5388
return fn.apply(self, args);
}
function instantiate(Type, locals, serviceName) {
// Check if Type is annotated and use just the given function at n-1 as parameter
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
// Object creation: http://jsperf.com/create-constructor/2
var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
var returnedValue = invoke(Type, instance, locals, serviceName);
return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
}
return {
invoke: invoke,
instantiate: instantiate,
get: getService,
annotate: createInjector.$$annotate,
has: function(name) {
return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
}
};
}
provider、 factory、service
有代码可知factory只是用provider方法进行包装
而service在factory包装的基础上通过 $injector.instantiate返回一个实例话对象
function provider(name, provider_) {
assertNotHasOwnProperty(name, 'service');
if (isFunction(provider_) || isArray(provider_)) {
provider_ = providerInjector.instantiate(provider_);
}
if (!provider_.$get) {
throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
}
return providerCache[name + providerSuffix] = provider_;
}
function factory(name, factoryFn, enforce) {
return provider(name, {
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
});
}
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
网友评论