AngularJS 源码分析3

本文接着上一篇讲



回顾


上次说到了rootScope里的$watch方法中的解析监控表达式,即而引出了对parse的分析,今天我们接着这里继续挖代码.

$watch续

先上一块$watch代码

?





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

$watch: function(watchExp, listener, objectEquality) {

        var
scope = this,

            get = compileToFn(watchExp, ‘watch‘),

            array = scope.$$watchers,

            watcher = {

              fn: listener,

              last: initWatchVal,

              get: get,

              exp: watchExp,

              eq: !!objectEquality

            };

        lastDirtyWatch = null;

        // in the case user pass string, we need to compile it, do we really need this ?

        if
(!isFunction(listener)) {

          var
listenFn = compileToFn(listener || noop, ‘listener‘);

          watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};

        }

        if
(typeof watchExp == ‘string‘
&& get.constant) {

          var
originalFn = watcher.fn;

          watcher.fn = function(newVal, oldVal, scope) {

            originalFn.call(this, newVal, oldVal, scope);

            arrayRemove(array, watcher);

          };

        }

        if
(!array) {

          array = scope.$$watchers = [];

        }

        // we use unshift since we use a while loop in $digest for speed.

        // the while loop reads in reverse order.

        array.unshift(watcher);

        return
function deregisterWatch() {

          arrayRemove(array, watcher);

          lastDirtyWatch = null;

        };

      }

这里的get = compileToFn(watchExp,
‘watch‘),上篇已经分析完了,这里返回的是一个执行表达式的函数,接着往下看,这里初始化了一个watcher对象,用来保存一些监听相关的信息,简单的说明一下

  • fn, 代表监听函数,当监控表达式新旧不相等时会执行此函数

  • last, 保存最后一次发生变化的监控表达式的值

  • get, 保存一个监控表达式对应的函数,目的是用来获取表达式的值然后用来进行新旧对比的

  • exp, 保存一个原始的监控表达式

  • eq, 保存$watch函数的第三个参数,表示是否进行深度比较

然后会检查传递进来的监听参数是否为函数,如果是一个有效的字符串,则通过parse来解析生成一个函数,否则赋值为一个noop占位函数,最后生成一个包装函数,函数体的内容就是执行刚才生成的监听函数,默认传递当前作用域.

接着会检查监控表达式是否为字符串并且执行表达式的constant为true,代表这个字符串是一个常量,那么,系统在处理这种监听的时候,执行完一次监听函数之后就会删除这个$watch.最后往当前作用域里的$$watchers数组头中添加$watch信息,注意这里的返回值,利用JS的闭包保留了当前的watcher,然后返回一个函数,这个就是用来删除监听用的.

$eval

这个$eval也是挺方便的函数,假如你想直接在程序里执行一个字符串的话,那么可以这么用

?





1

2

$scope.name = ‘2‘;

$scope.$eval(‘1+name‘); // ==> 会输出12

大家来看看它的函数体

?





1

return $parse(expr)(this, locals);

其实就是通过parse来解析成一个执行表达式函数,然后传递当前作用域以及额外的参数,返回这个执行表达式函数的值

$evalAsync

evalAsync函数的作用就是延迟执行表达式,并且执行完不管是否异常,触发dirty check.

?





1

2

3

4

5

6

7

8

9

if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) {

          $browser.defer(function() {

            if
($rootScope.$$asyncQueue.length) {

              $rootScope.$digest();

            }

          });

        }

this.$$asyncQueue.push({scope: this, expression: expr});

可以看到当前作用域内部有一个$$asyncQueue异步队列,保存着所有需要延迟执行的表达式,此处的表达式可以是字符串或者函数,因为这个表达式最终会调用$eval方法,注意这里调用了$browser服务的defer方法,从ng->browser.js源码里可以看到,其实这里就是调用setTimeout来实现的.

?





1

2

3

4

5

6

7

8

9

10

self.defer = function(fn, delay) {

    var
timeoutId;

    outstandingRequestCount++;

    timeoutId = setTimeout(function() {

      delete
pendingDeferIds[timeoutId];

      completeOutstandingRequest(fn);

    }, delay || 0);

    pendingDeferIds[timeoutId] = true;

    return
timeoutId;

  };

上面的代码主要是延迟执行函数,另外pendingDeferIds对象保存所有setTimeout返回的id,这个会在self.defer.cancel这里可以取消执行延迟执行.

说digest方法之前,还有一个方法要说说

$postDigest

这个方法跟evalAsync不同的时,它不会主动触发digest方法,只是往postDigestQueue队列中增加执行表达式,它会在digest体内最后执行,相当于在触发dirty
check之后,可以执行别的一些逻辑.

?





1

this.$$postDigestQueue.push(fn);

下面我们来重点说说digest方法

$digest

digest方法是dirty
check的核心,主要思路是先执行$$asyncQueue队列中的表达式,然后开启一个loop来的执行所有的watch里的监听函数,前提是前后两次的值是否不相等,假如ttl超过系统默认值,则dirth
check结束,最后执行$$postDigestQueue队列里的表达式.

?





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

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

$digest: function() {

        var
watch, value, last,

            watchers,

            asyncQueue = this.$$asyncQueue,

            postDigestQueue = this.$$postDigestQueue,

            length,

            dirty, ttl = TTL,

            next, current, target = this,

            watchLog = [],

            logIdx, logMsg, asyncTask;

        beginPhase(‘$digest‘);

        lastDirtyWatch = null;

        do
{ // "while dirty" loop

          dirty = false;

          current = target;

          while(asyncQueue.length) {

            try
{

              asyncTask = asyncQueue.shift();

              asyncTask.scope.$eval(asyncTask.expression);

            } catch
(e) {

              clearPhase();

              $exceptionHandler(e);

            }

            lastDirtyWatch = null;

          }

          traverseScopesLoop:

          do
{ // "traverse the scopes" loop

            if
((watchers = current.$$watchers)) {

              // process our watches

              length = watchers.length;

              while
(length--) {

                try
{

                  watch = watchers[length];

                  // Most common watches are on primitives, in which case we can short

                  // circuit it with === operator, only when === fails do we use .equals

                  if
(watch) {

                    if
((value = watch.get(current)) !== (last = watch.last) &&

                        !(watch.eq

                            ? equals(value, last)

                            : (typeof
value == ‘number‘
&& typeof
last == ‘number‘

                               && isNaN(value) && isNaN(last)))) {

                      dirty = true;

                      lastDirtyWatch = watch;

                      watch.last = watch.eq ? copy(value) : value;

                      watch.fn(value, ((last === initWatchVal) ? value : last), current);

                      if
(ttl < 5) {

                        logIdx = 4 - ttl;

                        if
(!watchLog[logIdx]) watchLog[logIdx] = [];

                        logMsg = (isFunction(watch.exp))

                            ? ‘fn: ‘
+ (watch.exp.name || watch.exp.toString())

                            : watch.exp;

                        logMsg += ‘; newVal: ‘
+ toJson(value) + ‘; oldVal: ‘
+ toJson(last);

                        watchLog[logIdx].push(logMsg);

                      }

                    } else
if (watch === lastDirtyWatch) {

                      // If the most recently dirty watcher is now clean, short circuit since the remaining watchers

                      // have already been tested.

                      dirty = false;

                      break
traverseScopesLoop;

                    }

                  }

                } catch
(e) {

                  clearPhase();

                  $exceptionHandler(e);

                }

              }

            }

            // Insanity Warning: scope depth-first traversal

            // yes, this code is a bit crazy, but it works and we have tests to prove it!

            // this piece should be kept in sync with the traversal in $broadcast

            if
(!(next = (current.$$childHead ||

                (current !== target && current.$$nextSibling)))) {

              while(current !== target && !(next = current.$$nextSibling)) {

                current = current.$parent;

              }

            }

          } while
((current = next));

          // break traverseScopesLoop; takes us to here

          if((dirty || asyncQueue.length) && !(ttl--)) {

            clearPhase();

            throw
$rootScopeMinErr(‘infdig‘,

                ‘{0} $digest() iterations reached. Aborting!\n‘
+

                ‘Watchers fired in the last 5 iterations: {1}‘,

                TTL, toJson(watchLog));

          }

        } while
(dirty || asyncQueue.length);

        clearPhase();

        while(postDigestQueue.length) {

          try
{

            postDigestQueue.shift()();

          } catch
(e) {

            $exceptionHandler(e);

          }

        }

      }

通过上面的代码,可以看出,核心就是两个loop,外loop保证所有的model都能检测到,内loop则是真实的检测每个watch,watch.get就是计算监控表达式的值,这个用来跟旧值进行对比,假如不相等,则执行监听函数

注意这里的watch.eq这是是否深度检查的标识,equals方法是angular.js里的公共方法,用来深度对比两个对象,这里的不相等有一个例外,那就是NaN
===NaN,因为这个永远都是false,所以这里加了检查

?





1

2

3

4

!(watch.eq

    ? equals(value, last)

    : (typeof
value == ‘number‘
&& typeof
last == ‘number‘

       && isNaN(value) && isNaN(last)))

比较完之后,把新值传给watch.last,然后执行watch.fn也就是监听函数,传递三个参数,分别是:最新计算的值,上次计算的值(假如是第一次的话,则传递新值),最后一个参数是当前作用域实例,这里有一个设置外loop的条件值,那就是dirty
=
true,也就是说只要内loop执行了一次watch,则外loop还要接着执行,这是为了保证所有的model都能监测一次,虽然这个有点浪费性能,不过超过ttl设置的值后,dirty
check会强制关闭,并抛出异常

?





1

2

3

4

5

6

7

if((dirty || asyncQueue.length) && !(ttl--)) {

    clearPhase();

    throw
$rootScopeMinErr(‘infdig‘,

        ‘{0} $digest() iterations reached. Aborting!\n‘
+

        ‘Watchers fired in the last 5 iterations: {1}‘,

        TTL, toJson(watchLog));

}

这里的watchLog日志对象是在内loop里,当ttl低于5的时候开始记录的

?





1

2

3

4

5

6

7

8

9

if (ttl < 5) {

    logIdx = 4 - ttl;

    if
(!watchLog[logIdx]) watchLog[logIdx] = [];

    logMsg = (isFunction(watch.exp))

        ? ‘fn: ‘
+ (watch.exp.name || watch.exp.toString())

        : watch.exp;

    logMsg += ‘; newVal: ‘
+ toJson(value) + ‘; oldVal: ‘
+ toJson(last);

    watchLog[logIdx].push(logMsg);

}

当检查完一个作用域内的所有watch之后,则开始深度遍历当前作用域的子级或者父级,虽然这有些影响性能,就像这里的注释写的那样yes, this code
is a bit crazy

?





1

2

3

4

5

6

7

8

9

// Insanity Warning: scope depth-first traversal

// yes, this code is a bit crazy, but it works and we have tests to prove it!

// this piece should be kept in sync with the traversal in $broadcast

if (!(next = (current.$$childHead ||

      (current !== target && current.$$nextSibling)))) {

    while(current !== target && !(next = current.$$nextSibling)) {

      current = current.$parent;

    }

}

上面的代码其实就是不断的查找当前作用域的子级,没有子级,则开始查找兄弟节点,最后查找它的父级节点,是一个深度遍历查找.只要next有值,则内loop则一直执行

?





1

while ((current = next))

不过内loop也有跳出的情况,那就是当前watch跟最后一次检查的watch相等时就退出内loop.

?





1

2

3

4

5

6

else
if (watch === lastDirtyWatch) {

    // If the most recently dirty watcher is now clean, short circuit since the remaining watchers

    // have already been tested.

    dirty = false;

    break
traverseScopesLoop;

}

注意这个内loop同时也是一个label(标签)语句,这个可以在loop中执行跳出操作就像上面的break

正常执行完两个loop之后,清除当前的阶段标识clearPhase();,然后开始执行postDigestQueue队列里的表达式.

?





1

2

3

4

5

6

7

while(postDigestQueue.length) {

    try
{

      postDigestQueue.shift()();

    } catch
(e) {

      $exceptionHandler(e);

    }

}

接下来说说,用的也比较多的$apply方法

$apply

这个方法一般用在,不在ng的上下文中执行js代码的情况,比如原生的DOM事件中执行想改变ng中某些model的值,这个时候就要使用$apply方法了

?





1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

$apply: function(expr) {

    try
{

      beginPhase(‘$apply‘);

      return
this.$eval(expr);

    } catch
(e) {

      $exceptionHandler(e);

    } finally {

      clearPhase();

      try
{

        $rootScope.$digest();

      } catch
(e) {

        $exceptionHandler(e);

        throw
e;

      }

    }

}

代码中,首先让当前阶段标识为$apply,这个可以防止使用$apply方法时检查是否已经在这个阶段了,然后就是执行$eval方法,
这个方法上面有讲到,最后执行$digest方法,来使ng中的M或者VM改变.

接下来说说scope中event模块,它的api跟一般的event事件模块比较像,提供有$on,$emit,$broadcast,这三个很实用的方法

$on

这个方法是用来定义事件的,这里用到了两个实例变量$$listeners, $$listenerCount,分别用来保存事件,以及事件数量计数

?





1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

$on: function(name, listener) {

        var
namedListeners = this.$$listeners[name];

        if
(!namedListeners) {

          this.$$listeners[name] = namedListeners = [];

        }

        namedListeners.push(listener);

        var
current = this;

        do
{

          if
(!current.$$listenerCount[name]) {

            current.$$listenerCount[name] = 0;

          }

          current.$$listenerCount[name]++;

        } while
((current = current.$parent));

        var
self = this;

        return
function() {

          namedListeners[indexOf(namedListeners, listener)] = null;

          decrementListenerCount(self, 1, name);

        };

      }

分析上面的代码,可以看出每当定义一个事件的时候,都会向$$listeners对象中添加以name为key的属性,值就是事件执行函数,注意这里有个事件计数,只要有父级,则也给父级的$$listenerCount添加以name为key的属性,并且值+1,这个$$listenerCount
会在广播事件的时候用到,最后这个方法返回一个取消事件的函数,先设置$$listeners中以name为key的值为null,然后调用decrementListenerCount来使该事件计数-1.

$emit

这个方法是用来触发$on定义的事件,原理就是loop$$listeners属性,检查是否有值,有的话,则执行,然后依次往上检查父级,这个方法有点类似冒泡执行事件.

$emit: function(name, args) { var empty = [],
namedListeners, scope = this, stopPropagation = false,
event = { name: name, targetScope: scope,
stopPropagation: function() {stopPropagation = true;},
preventDefault: function() { event.defaultPrevented = true;
}, defaultPrevented: false },
listenerArgs = concat([event], arguments, 1), i, length;

    do {
namedListeners = scope.$$listeners[name] || empty;
event.currentScope = scope;
for (i=0, length=namedListeners.length; i<length; i++) {

// if listeners were deregistered, defragment the array
if (!namedListeners[i]) {
namedListeners.splice(i, 1);
i--;
length--;
continue;
}
try {
//allow all listeners attached to the current scope to run
namedListeners[i].apply(null, listenerArgs);
} catch (e) {
$exceptionHandler(e);
}
}
//if any listener on the current scope stops propagation, prevent bubbling
if (stopPropagation) return event;
//traverse upwards
scope = scope.$parent;
} while (scope);

return event;
}


上面的代码比较简单,首先定义一个事件参数,然后开启一个loop,只要scope有值,则一直执行,这个方法的事件链是一直向上传递的,不过当在事件函数执行stopPropagation方法,就会停止向上传递事件.

$broadcast

这个是$emit的升级版,广播事件,即能向上传递,也能向下传递,还能平级传递,核心原理就是利用深度遍历当前作用域

$broadcast: function(name, args) { var target = this, current =
target, next = target, event = { name: name,
targetScope: target, preventDefault: function() {
event.defaultPrevented = true; }, defaultPrevented: false
}, listenerArgs = concat([event], arguments, 1), listeners, i,
length;

//down while you can, then up and next sibling or up and next sibling until back at root
while ((current = next)) {
event.currentScope = current;
listeners = current.$$listeners[name] || [];
for (i=0, length = listeners.length; i<length; i++) {
// if listeners were deregistered, defragment the array
if (!listeners[i]) {
listeners.splice(i, 1);
i--;
length--;
continue;
}

try {
listeners[i].apply(null, listenerArgs);
} catch(e) {
$exceptionHandler(e);
}
}

// Insanity Warning: scope depth-first traversal
// yes, this code is a bit crazy, but it works and we have tests to prove it!
// this piece should be kept in sync with the traversal in $digest
// (though it differs due to having the extra check for $$listenerCount)
if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
(current !== target && current.$$nextSibling)))) {
while(current !== target && !(next = current.$$nextSibling)) {
current = current.$parent;
}
}
}

return event;


}

代码跟$emit差不多,只是跟它不同的时,这个是不断的取next值,而next的值则是通过深度遍历它的子级节点,兄弟节点,父级节点,依次查找可用的以name为key的事件.注意这里的注释,跟$digest里的差不多,都是通过深度遍历查找,所以$broadcast方法也不能常用,性能不是很理想

$destroy

这个方法是用来销毁当前作用域,代码主要是清空当前作用域内的一些实例属性,以免执行digest,$emit,$broadcast时会关联到

?





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

$destroy: function() {

    // we can‘t destroy the root scope or a scope that has been already destroyed

    if
(this.$$destroyed) return;

    var
parent = this.$parent;

    this.$broadcast(‘$destroy‘);

    this.$$destroyed = true;

    if (this === $rootScope) return;

    forEach(this.$$listenerCount, bind(null, decrementListenerCount, this));

    // sever all the references to parent scopes (after this cleanup, the current scope should

    // not be retained by any of our references and should be eligible for garbage collection)

    if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;

    if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;

    if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;

    if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;

    // All of the code below is bogus code that works around V8‘s memory leak via optimized code

    // and inline caches.

    //

    // see:

    // - https://code.google.com/p/v8/issues/detail?id=2073#c26

    // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909

    // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451

    this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =

        this.$$childTail = this.$root = null;

    // don‘t reset these to null in case some async task tries to register a listener/watch/task

    this.$$listeners = {};

    this.$$watchers = this.$$asyncQueue = this.$$postDigestQueue = [];

    // prevent NPEs since these methods have references to properties we nulled out

    this.$destroy = this.$digest = this.$apply = noop;

    this.$on = this.$watch = function() { return
noop; };

}

代码比较简单,先是通过foreach来清空$$listenerCount实例属性,然后再设置$parent,$$nextSibling,$$prevSibling,$$childHead,$$childTail,$root为null,清空$$listeners,$$watchers,$$asyncQueue,$$postDigestQueue,最后就是重罢方法为noop占位函数

总结

rootScope说完了,这是个使用比例非常高的核心provider,分析的比较简单,有啥错误的地方,希望大家能够指出来,大家一起学习学习,下次有空接着分析别的.


作者声明


作者: feenan

出处: http://www.cnblogs.com/xuwenmin888

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。


AngularJS 源码分析3,布布扣,bubuko.com

时间: 2024-12-18 21:57:13

AngularJS 源码分析3的相关文章

angularjs源码分析之:angularjs执行流程

angularjs用了快一个月了,最难的不是代码本身,而是学会怎么用angular的思路思考问题.其中涉及到很多概念,比如:directive,controller,service,compile,link,scope,isolate scope,双向绑定,mvvm等.最近准备把这些都慢慢搞懂,分析源码并贴到博客园,如有分析不对的地方,还望各位包容并指正. angularjs源码分析之:angularjs执行流程 先上个大图,有个大概印象,注:angularjs的版本为:1.2.1,通过bowe

AngularJS 源码分析1

AngularJS简介 angularjs 是google出品的一款MVVM前端框架,包含一个精简的类jquery库,创新的开发了以指令的方式来组件化前端开发,可以去它的官网看看,请戳这里 再贴上一个本文源码分析对应的angularjs源码合并版本1.2.4,精简版的,除掉了所有的注释, 请戳这里 从启动开始说起 定位到4939行,这里是angularjs开始执行初始化的地方,见代码 ? 1 2 3 bindJQuery(), publishExternalAPI(angular), jqLit

Angularjs 源码分析2

本文主要分析RootScopeProvider和ParseProvider RootScopeProvider简介 今天这个rootscope可是angularjs里面比较活跃的一个provider,大家可以理解为一个模型M或者VM,它主要负责与控制器或者指令进行数据交互. 今天使用的源码跟上次分析的一样也是1.2.X系列,只不过这次用的是未压缩合并版的,方便大家阅读,可以在这里下载 从$get属性说起 说起这个$get属性,是每个系统provider都有的,主要是先保存要实例化的函数体,等待i

MVVM大比拼之AngularJS源码精析

MVVM大比拼之AngularJS源码精析 简介 AngularJS的学习资源已经非常非常多了,AngularJS基础请直接看官网文档.这里推荐几个深度学习的资料: AngularJS学习笔记 作者:邹业盛 .这个笔记非常细致,记录了作者对于AngularJS各个方面的思考,其中也不乏源码级的分析. 构建自己的AngularJS .虽然放出第一章后作者就写书去了.但这第一部分已经足以带领读者深入窥探angularJS在核心概念上的实现,特别是dirty check.有愿意继续深入的读者可以去买书

TeamTalk源码分析之login_server

login_server是TeamTalk的登录服务器,负责分配一个负载较小的MsgServer给客户端使用,按照新版TeamTalk完整部署教程来配置的话,login_server的服务端口就是8080,客户端登录服务器地址配置如下(这里是win版本客户端): 1.login_server启动流程 login_server的启动是从login_server.cpp中的main函数开始的,login_server.cpp所在工程路径为server\src\login_server.下表是logi

Android触摸屏事件派发机制详解与源码分析二(ViewGroup篇)

1 背景 还记得前一篇<Android触摸屏事件派发机制详解与源码分析一(View篇)>中关于透过源码继续进阶实例验证模块中存在的点击Button却触发了LinearLayout的事件疑惑吗?当时说了,在那一篇咱们只讨论View的触摸事件派发机制,这个疑惑留在了这一篇解释,也就是ViewGroup的事件派发机制. PS:阅读本篇前建议先查看前一篇<Android触摸屏事件派发机制详解与源码分析一(View篇)>,这一篇承接上一篇. 关于View与ViewGroup的区别在前一篇的A

HashMap与TreeMap源码分析

1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Java这么久,也写过一些小项目,也使用过TreeMap无数次,但到现在才明白它的实现原理).因此本着"不要重复造轮子"的思想,就用这篇博客来记录分析TreeMap源码的过程,也顺便瞅一瞅HashMap. 2. 继承结构 (1) 继承结构 下面是HashMap与TreeMap的继承结构: pu

Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938395.html 前面粗略分析start_kernel函数,此函数中基本上是对内存管理和各子系统的数据结构初始化.在内核初始化函数start_kernel执行到最后,就是调用rest_init函数,这个函数的主要使命就是创建并启动内核线

Spark的Master和Worker集群启动的源码分析

基于spark1.3.1的源码进行分析 spark master启动源码分析 1.在start-master.sh调用master的main方法,main方法调用 def main(argStrings: Array[String]) { SignalLogger.register(log) val conf = new SparkConf val args = new MasterArguments(argStrings, conf) val (actorSystem, _, _, _) =