AngularJS 源码分析1
2020-12-13 05:18
标签:style blog class code c tar angularjs
是google出品的一款MVVM前端框架,包含一个精简的类jquery库,创新的开发了以指令的方式来组件化前端开发,可以去它的官网看看,请戳这里 再贴上一个本文源码分析对应的angularjs源码合并版本1.2.4,精简版的,除掉了所有的注释, 请戳这里 定位到4939行,这里是angularjs开始执行初始化的地方,见代码
bindJQuery方法是检查是否引用jquery,没有的话jqlite就用本身自带的,否则切换到jquery中去.这个好理解 publishExternalAPI这个方法是绑定一些公共的方法到angular下面,这些是可以在网站中访问到的,像forEach,copy等公共方法,还有一个重要的任务就是初始化angular核心的模块,publishExternalAPI在465行,现在我们来分析里面的一些重要的代码
方法体中的setupModuleLoader方法是一个模块加载器,这也是一个关键方法, 主要作用是创建和获取模块,代码见417行.
上面publishExternalAPI 方法中的angularModule =
setupModuleLoader(window);是在window下面创建全局的angular对象,并且返回一个高阶函数,赋值给了angular.module属性,所以一般我们创建模块都是用angular.module方法.这里的angularModule其实就是相当于angular.module angular.module在创建模块的时候,传递一个参数的时候,是获取模块;传递一个以上的是创建新模块;该方法返回的是一个moduleInstance对象,它的任务就是来创建控制器,服务,指令,以及配置方法,全局运行方法,而且是链式调用,因为每个方法都会返回moduleInstance,看这里
此处的return invokeQueue[insertMethod || "push"]([provider, method, arguments]),
moduleInstance,逗号表达式是返回最后一个值 再来一个angular.module在项目中运用的代码
接下来再看publishExternalAPI的代码,因为ngLocale默认没有创建,所以angularModule("ngLocale")这个直接异常,跳到catch里执行angularModule("ngLocale",
[]).provider("$locale",
$LocaleProvider),记住这里的provider方法,默认是把它的参数都存到invokeQueue数组中,以便在后面用到. 接下来开始创建ng模块,它依赖上面的ngLocale模块,注意创建模块的时候传了第三个参数,当创建模块的时候传了三个参数,默认第三参数会执行config(configFn),这个方法也是把相应的参数放入invokeQueue数组中,只不过前两参数是$injector,invoke,这里先透露一下,其实所有invokeQueue数组项中,三个参数的意思:第一个参数调用第二个参数,然后传递第三个参数,这个后面会讲到. 这里说下ng模块中第三个参数里的函数体,这里主要做了两件事,初始了$compile服务,并且利用compile服务的directive方法,把一些常用的指令都保存到compile服务中的一个内部数组中. 这里先说下$provide.provider,这个在angular里用的比较多,其实就是提前把定义的provider放入DI函数内的providerCache内,看如下代码,在740行
AngularJS简介
从启动开始说起
bindJQuery(), publishExternalAPI(angular), jqLite(document).ready(
function
() {
angularInit(document, bootstrap)
})
function
publishExternalAPI(angular) {
extend(angular, {
bootstrap: bootstrap,
copy: copy,
extend: extend,
equals: equals,
element: jqLite,
forEach: forEach,
injector: createInjector,
noop: noop,
bind: bind,
toJson: toJson,
fromJson: fromJson,
identity: identity,
isUndefined: isUndefined,
isDefined: isDefined,
isString: isString,
isFunction: isFunction,
isObject: isObject,
isNumber: isNumber,
isElement: isElement,
isArray: isArray,
version: version,
isDate: isDate,
lowercase: lowercase,
uppercase: uppercase,
callbacks: {
counter: 0
},
$$minErr: minErr,
$$csp: csp
}), angularModule = setupModuleLoader(window);
try
{
angularModule(
"ngLocale"
)
}
catch
(e) {
angularModule(
"ngLocale"
, []).provider(
"$locale"
, $LocaleProvider)
}
angularModule(
"ng"
, [
"ngLocale"
], [
"$provide"
,
function
($provide) {
$provide.provider(
"$compile"
, $CompileProvider).directive({
a: htmlAnchorDirective,
input: inputDirective,
textarea: inputDirective,
form: formDirective,
script: scriptDirective,
select: selectDirective,
style: styleDirective,
option: optionDirective,
ngBind: ngBindDirective,
ngBindHtml: ngBindHtmlDirective,
ngBindTemplate: ngBindTemplateDirective,
ngClass: ngClassDirective,
ngClassEven: ngClassEvenDirective,
ngClassOdd: ngClassOddDirective,
ngCloak: ngCloakDirective,
ngController: ngControllerDirective,
ngForm: ngFormDirective,
ngHide: ngHideDirective,
ngIf: ngIfDirective,
ngInclude: ngIncludeDirective,
ngInit: ngInitDirective,
ngNonBindable: ngNonBindableDirective,
ngPluralize: ngPluralizeDirective,
ngRepeat: ngRepeatDirective,
ngShow: ngShowDirective,
ngStyle: ngStyleDirective,
ngSwitch: ngSwitchDirective,
ngSwitchWhen: ngSwitchWhenDirective,
ngSwitchDefault: ngSwitchDefaultDirective,
ngOptions: ngOptionsDirective,
ngTransclude: ngTranscludeDirective,
ngModel: ngModelDirective,
ngList: ngListDirective,
ngChange: ngChangeDirective,
required: requiredDirective,
ngRequired: requiredDirective,
ngValue: ngValueDirective
}).directive(ngAttributeAliasDirectives).directive(ngEventDirectives), $provide.provider({
$anchorScroll: $AnchorScrollProvider,
$animate: $AnimateProvider,
$browser: $BrowserProvider,
$cacheFactory: $CacheFactoryProvider,
$controller: $ControllerProvider,
$document: $DocumentProvider,
$exceptionHandler: $ExceptionHandlerProvider,
$filter: $FilterProvider,
$interpolate: $InterpolateProvider,
$interval: $IntervalProvider,
$http: $HttpProvider,
$httpBackend: $HttpBackendProvider,
$location: $LocationProvider,
$log: $LogProvider,
$parse: $ParseProvider,
$rootScope: $RootScopeProvider,
$q: $QProvider,
$sce: $SceProvider,
$sceDelegate: $SceDelegateProvider,
$sniffer: $SnifferProvider,
$templateCache: $TemplateCacheProvider,
$timeout: $TimeoutProvider,
$window: $WindowProvider
})
}
])
}
function
setupModuleLoader(window) {
function
ensure(obj, name, factory) {
return
obj[name] || (obj[name] = factory())
}
var
$injectorMinErr = minErr(
"$injector"
),
ngMinErr = minErr(
"ng"
);
return
ensure(ensure(window,
"angular"
, Object),
"module"
,
function
() {
var
modules = {};
return
function
(name, requires, configFn) {
var
assertNotHasOwnProperty =
function
(name, context) {
if
(
"hasOwnProperty"
=== name)
throw
ngMinErr(
"badname"
,
"hasOwnProperty is not a valid {0} name"
, context)
};
return
assertNotHasOwnProperty(name,
"module"
), requires && modules.hasOwnProperty(name) && (modules[name] =
null
), ensure(modules, name,
function
() {
function
invokeLater(provider, method, insertMethod) {
return
function
() {
return
invokeQueue[insertMethod ||
"push"
]([provider, method, arguments]), moduleInstance
}
}
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 = [],
runBlocks = [],
config = invokeLater(
"$injector"
,
"invoke"
),
moduleInstance = {
_invokeQueue: invokeQueue,
_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) {
return
runBlocks.push(block),
this
}
};
return
configFn && config(configFn), moduleInstance
})
}
})
}
function
invokeLater(provider, method, insertMethod) {
return
function
() {
return
invokeQueue[insertMethod ||
"push"
]([provider, method, arguments]), moduleInstance
}
}
angular.module(
‘demoApp‘
, [])
.factory()
.controller()
.directive()
.config()
.run();
function
createInjector(modulesToLoad) {
function
supportObject(delegate) {
return
function
(key, value) {
return
isObject(key) ? (forEach(key, reverseParams(delegate)), void 0) : delegate(key, value)
}
}
function
provider(name, provider_) {
if
(assertNotHasOwnProperty(name,
"service"
), (isFunction(provider_) || isArray(provider_)) && (provider_ = providerInjector.instantiate(provider_)), !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
})
}
}
function
loadModules(modulesToLoad) {
var
moduleFn, invokeQueue, i, ii, runBlocks = [];
return
forEach(modulesToLoad,
function
(module) {
if
(!loadedModules.get(module)) {
loadedModules.put(module, !0);
try
{
if
(isString(module))
for
(moduleFn = angularModule(module), runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks), invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; ii > i; i++) {
var
invokeArgs = invokeQueue[i],
provider = providerInjector.get(invokeArgs[0]);
provider[invokeArgs[1]].apply(provider, invokeArgs[2])
}
else
isFunction(module) ? runBlocks.push(providerInjector.invoke(module)) : isArray(module) ? runBlocks.push(providerInjector.invoke(module)) : assertArgFn(module,
"module"
)
}
catch
(e) {
throw
isArray(module) && (module = module[module.length - 1]), e.message && e.stack && -1 == e.stack.indexOf(e.message) && (e = e.message +
"\n"
+ e.stack), $injectorMinErr(
"modulerr"
,
"Failed to instantiate module {0} due to:\n{1}"
, module, e.stack || e.message || e)
}
}
}),runBlocks
}
function
createInternalInjector(cache, factory) {
function
getService(serviceName) {
if
(cache.hasOwnProperty(serviceName)) {
if
(cache[serviceName] === INSTANTIATING)
throw
$injectorMinErr(
"cdep"
,
"Circular dependency found: {0}"
, path.join(
"
));
return
cache[serviceName]
}
try
{
return
path.unshift(serviceName), cache[serviceName] = INSTANTIATING, cache[serviceName] = factory(serviceName)
} finally {
path.shift()
}
}
function
invoke(fn, self, locals) {
var
length, i, key, args = [],
$inject = annotate(fn);
for
(i = 0, length = $inject.length; length > i; i++) {
if
(key = $inject[i],
"string"
!=
typeof
key)
throw
$injectorMinErr(
"itkn"
,
"Incorrect injection token! Expected service name as string, got {0}"
, key);
args.push(locals && locals.hasOwnProperty(key) ? locals[key] : getService(key))
}
switch
(fn.$inject || (fn = fn[length]), self ? -1 : args.length) {
case
0:
return
fn();
case
1:
return
fn(args[0]);
case
2:
return
fn(args[0], args[1]);
case
3:
return
fn(args[0], args[1], args[2]);
case
4:
return
fn(args[0], args[1], args[2], args[3]);
case
5:
return
fn(args[0], args[1], args[2], args[3], args[4]);
case
6:
return
fn(args[0], args[1], args[2], args[3], args[4], args[5]);
case
7:
return
fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
case
8:
return
fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
case
9:
return
fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
case
10:
return
fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
default
:
return
fn.apply(self, args)
}
}
function
instantiate(Type, locals) {
var
instance, returnedValue, Constructor =
function
() {};
return
Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype, instance =
new
Constructor, returnedValue = invoke(Type, instance, locals), 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)
}
}
}
>
上一篇:C++--同名覆盖、多态