angular初始化过程
页面加载完成调用angularInit
跟jquery中的ready函数很像吧1
2
3jqLite(window.document).ready(function() {
angularInit(window.document, bootstrap);
});
jqLite.ready函数
1 | var JQLitePrototype = JQLite.prototype = { |
angularInit
1 | //element元素 ,从上文看就是window.document |
bootstrap
最终调用的还是bootstrap函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72function bootstrap(element, modules, config) {
if (!isObject(config)) config = {};
var defaultConfig = {
strictDi: false
};
//扩展默认配置
config = extend(defaultConfig, config);
var doBootstrap = function() {
element = jqLite(element);//用jqLite包装下
//判断injector方法调用的结果
//一开始调用element.injector()时是返回false的,当调用到
//element.data('$injector', injector);就为true了
if (element.injector()) {
var tag = (element[0] === window.document) ? 'document' : startingTag(element);
// Encode angle brackets to prevent input from being sanitized to empty string #8683.
throw ngMinErr(
'btstrpd',
"App already bootstrapped with this element '{0}'",
tag.replace(/</,'<').replace(/>/,'>'));
}
modules = modules || [];
//unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。
modules.unshift(['$provide', function($provide) {
$provide.value('$rootElement', element);
}]);
if (config.debugInfoEnabled) {
// Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
modules.push(['$compileProvider', function($compileProvider) {
$compileProvider.debugInfoEnabled(true);
}]);
}
//ng模块放入第一位
modules.unshift('ng');
var injector = createInjector(modules, config.strictDi);
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
function bootstrapApply(scope, element, compile, injector) {
scope.$apply(function() {
element.data('$injector', injector);
compile(element)(scope);
});
}]
);
return injector;
};
var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
config.debugInfoEnabled = true;
window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
}
if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
return doBootstrap();
}
window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
angular.resumeBootstrap = function(extraModules) {
forEach(extraModules, function(module) {
modules.push(module);
});
return doBootstrap();
};
if (isFunction(angular.resumeDeferredBootstrap)) {
angular.resumeDeferredBootstrap();
}
}
element.injector在哪边定义的呢?
通过forEach遍历函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74//line 3347
forEach({
data: jqLiteData,
inheritedData: jqLiteInheritedData,
scope: function(element) {
// Can't use jqLiteData here directly so we stay compatible with jQuery!
return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
},
isolateScope: function(element) {
// Can't use jqLiteData here directly so we stay compatible with jQuery!
return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
},
controller: jqLiteController,
injector: function(element) {
return jqLiteInheritedData(element, '$injector');
}}, function(fn, name) {
//fn相当于value name相当于key
//jQLite.prototype['injector'] =
JQLite.prototype[name] = function(arg1, arg2) {
var i, key;
var nodeCount = this.length;
//jqLiteHasClass是个只读函数,所以需要特殊处理
// jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
// in a way that survives minification.
//缩小范围
// jqLiteEmpty takes no arguments but is a setter.
//jqLiteEmpty 无参函数 但是 是一个setter方法
if (fn !== jqLiteEmpty &&
(isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
if (isObject(arg1)) {
// we are a write, but the object properties are the key/values
for (i = 0; i < nodeCount; i++) {
if (fn === jqLiteData) {
// data() takes the whole object in jQuery
//this[i] 是通过jqLiteAddNodes函数往jqLite对象中加入索引
fn(this[i], arg1);
} else {
for (key in arg1) {
fn(this[i], key, arg1[key]);
}
}
}
// return self for chaining
return this;
} else {
//element.injector() 走到这里
// we are a read, so read the first child.
// TODO: do we still need this?
var value = fn.$dv;
// Only if we have $dv do we iterate over all, otherwise it is just the first element.
var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
for (var j = 0; j < jj; j++) {
var nodeValue = fn(this[j], arg1, arg2);
value = value ? value + nodeValue : nodeValue;
}
return value;
}
} else {
// we are a write, so apply to all children
for (i = 0; i < nodeCount; i++) {
fn(this[i], arg1, arg2);
}
// return self for chaining
return this;
}
};
});
jqLiteInheritedData
1 | function jqLiteInheritedData(element, name, value) { |
jqLite.data(jqLiteData):
1 | function jqLiteData(element, key, value) { |
jqLiteExpandoStore函数
1 | function jqLiteExpandoStore(element, createIfNecessary) { |
jqCache对象
var jqCache = JQLite.cache = {};