//这里分三大部分,
//分别是 provider(providerCache 和 instanceCache 与 providerInjector 和 instanceInjector) 是angualr 最核心的几个组件之一。
//loadModules
//createInternalInjector
function createInjector(modulesToLoad) {
var INSTANTIATING = {},
providerSuffix = 'Provider',
path = [],
loadedModules = new HashMap([], true),
//providerCache 基本保存所有组件,这里初始化了$provide组件,在初始化的时候,会加入很多组件
providerCache = {
$provide: {
provider: supportObject(provider),
factory: supportObject(factory),
service: supportObject(service),
value: supportObject(value),
constant: supportObject(constant),
decorator: decorator
}
},
//负责除了decorator组件之外所有组件注入
providerInjector = (providerCache.$injector =
createInternalInjector(providerCache, function() {
throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
})),
//基本没用,只保存了。constant组件的信息
instanceCache = {},
//负责decorator组件的注入,得到还是在providerCache 得到
instanceInjector = (instanceCache.$injector =
createInternalInjector(instanceCache, function(servicename) {
//注意,这里的代码与 getseriver方法的使用,
//等于 instanceInjector.getServer还是从providerInjector.get得到
var provider = providerInjector.get(servicename + providerSuffix);
return instanceInjector.invoke(provider.$get, provider);
}));
forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
return instanceInjector;
////////////////////////////////////
// $provider 组件包括factory,provider,service,value,constant,decorator,从这里就可以看到这些组件的不同之处。
////////////////////////////////////
function supportObject(delegate) {
return function(key, value) {
if (isObject(key)) {
forEach(key, reverseParams(delegate));
} else {
return delegate(key, value);
}
};
}
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) {
return provider(name, { $get: factoryFn });
}
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
function value(name, val) {
return factory(name, valueFn(val));
}
function constant(name, value) {
assertNotHasOwnProperty(name, 'constant');
providerCache[name] = value;
instanceCache[name] = value;
}
function decorator(serviceName, decorFn) {
var origProvider = providerInjector.get(serviceName + providerSuffix),
orig$get = origProvider.$get;
origProvider.$get = function() {
var origInstance = instanceInjector.invoke(orig$get, origProvider);
return instanceInjector.invoke(decorFn, null, { $delegate: origInstance });
};
}
////////////////////////////////////
// Module Loading
////////////////////////////////////
function loadModules(modulesToLoad) {
var runBlocks = [],
moduleFn, invokeQueue, i, ii;
forEach(modulesToLoad, function(module) {
if (loadedModules.get(module)) return;//如何依赖的组件已经初始化过,就不初始化了。
loadedModules.put(module, true);//加入缓存
try {
if (isString(module)) {
moduleFn = angularModule(module);//通过module名得到module的相关数据,等于angular.module(“”)
//loadModules(moduleFn.requires) 先加载依赖,同是把依赖的 run 方法 加入到runBlocks 中。
runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
//循环执行 module中的基础方法 ,在初始化,会加载很多provider,
for (invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
var invokeArgs = invokeQueue[i],
provider = providerInjector.get(invokeArgs[0]);
provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
}
} else if (isFunction(module)) {
runBlocks.push(providerInjector.invoke(module));
} else if (isArray(module)) {
runBlocks.push(providerInjector.invoke(module));
} else {
assertArgFn(module, 'module');
}
} catch (e) {
if (isArray(module)) {
module = module[module.length - 1];
}
if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
// Safari & FF's stack traces don't contain error.message content
// unlike those of Chrome and IE
// So if stack doesn't contain message, we create a new string that contains both.
// Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
/* jshint -W022 */
e = e.message + '\n' + e.stack;
}
throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
module, e.stack || e.message || e);
}
});
return runBlocks;
}
////////////////////////////////////
// internal Injector 注入器的实现 ,,缓存对象,与执行工厂,会实例化两个依赖注入对象,可以说白了,基本就等于一个。
////////////////////////////////////
function createInternalInjector(cache, factory) {
function getService(serviceName) {
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);
} catch (err) {
if (cache[serviceName] === INSTANTIATING) {
delete cache[serviceName];
}
throw err;
} finally {
path.shift();
}
}
}
//fn 执行的方法,locals方法需要的实参,self方法执行的上下文,也就是对象,也就是调用方法的this参数
function invoke(fn, self, locals) {
var args = [],
$inject = annotate(fn),
length, i,
key;
for (i = 0, length = $inject.length; i < length; i++) {
key = $inject[i];
if (typeof key !== 'string') {
throw $injectorMinErr('itkn',
'Incorrect injection token! Expected service name as string, got {0}', key);
}
//注意这里,如果参数在locals里面没有,就在 service里面得到。为什么有locals
// 比如 作用域不是服务,节点与属性也不是服务,只能从locals得到。
args.push(
locals && locals.hasOwnProperty(key) ? locals[key] : getService(key)
);
}
if (isArray(fn)) {
fn = fn[length];//注意这里,fn如果是数组那么最后一个才是执行的方法
}
// http://jsperf.com/angularjs-invoke-apply-vs-switch
// #5388
return fn.apply(self, args);
}
//这个方法 使用与invoke的区别就是使用了原型链而已,javascript这个语言就是麻烦。
function instantiate(Type, locals) {
var Constructor = function() {},
instance, returnedValue;
// 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) {}]);
Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
instance = new Constructor();
returnedValue = invoke(Type, instance, locals);//注意这里调用了 invoke 方法
return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
}
return {
invoke: invoke,
instantiate: instantiate,
get: getService,
annotate: annotate,
has: function(name) {
return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
}
};
}
}
相关推荐
Angular 的基本构造块是 NgModule,它为组件提供了编译的上下文环境。 NgModule 会把相关的代码收集 到一些功能集中。Angular 应用就是由一组 NgModule 定义出的。 应用至少会有一个用于引导应用的根模 块,通常还会...
角度音频上下文Web Audio API的AudioContext的Angular包装器。 除了作为包装器之外,该模块还修补了不存在的AudioContext和带前缀的AudioContext版本。 它使用来执行此操作。用法可以通过安装此模块,如下所示: npm...
简单的Noty包装器库,将Noty带入Angular上下文。 可凉亭式安装。 ##启动开发模式要运行演示,您需要安装gulp并将所有npm和bower deps安装到项目中。 npm install gulp -gnpm installbower installgulp ##如何在项目...
选择一个元素将启用一个新面板“ SB Angular”,该面板显示当前选定的元素:-组件-指令-侦听器-上下文-注入器如果它们适用于当前元素。 SB Angular Inspector还允许您修改“ SB Angular”面板中的值,然后使用此扩展...
#Angular 测试工具 用于 Angular 作用域、控制器和提供程序的测试工具。 简化通过为 Angular 单元测试注入依赖项而创建的样板。 抽象其他功能,并将设置和清理操作包装在易于使用的功能中。 ##Modules 默认加载ng ...
角材料启动器这是一个用于在 material.angularjs.org 上找到的新材料设计框架的样板启动项目使用什么Bower 用于管理所有组件依赖项角Angular ui 路由器角料角度动画,咏叹调在 moment 和 lodash 中添加,因为我总是...
角度上下文在Node应用程序中使用AngularJS。介绍是用于构建在Web浏览器中运行的单页应用程序的框架。 为了充分利用AngularJS的功能,它必须在浏览器中运行,但是可以在Node应用程序中使用AngularJS的子集。 存在此...
该插件支持元素和属性内容,绑定表达式,空格处理,翻译器上下文,内容排除等。 开箱即用地支持Aurelia和Angular模板,这意味着绑定表达式中任何类似HTML的内容都不会破坏HTML解析,并且可以轻松添加其他模板...
语言:English 您想记录和重播Web应用程序的请求,...不用担心,我们有一个chrome扩展程序,允许您在加载应用程序之后但在执行之前注入bsv配置(例如,对于angularjs,在创建angular上下文之后但在运行主控制器之前)。
ng-i18n-aot-loader [概念验证] 用于Webpack 2的angular i18n预加载器,可通过动态语言环境更改来... 所有绑定和上下文均保持不变,无需对代码进行特殊处理。 为了实际更改显示的语言环境,提供了一个服务(通过 )
该项目中的任何控制器都会返回一个Bluebird Promise,当它解决后,它通常是要发送给用户的有效负载,或者是要在页面模板中编译的上下文。 当Promise被拒绝时,通常是XError,它描述了用来应答用户的错误代码,HTTP...