我的以为,要很好的理解AngularJS的运行机制,才能尽量避免掉到坑里面去。在这篇文章中,我将根据网上的资料和本身的理解对AngularJS的在启动后,每一步都作了些什么,作一个比较清楚详细的解析。
首先上一小段代码(index.html),结合代码咱们来看看,angular一步一步都作了些什么。html
<!doctype html> <html ng-app> <head> <script src="angular.js"></script> </head> <body> <png-init=" name='World' ">Hello {{name}}!</p> </body> </html>
当你用浏览器去访问index.html的时候,浏览器依次作了以下一些事情:浏览器
整个过程能够用这张图来表示:服务器
好了,经过上面的例子咱们清楚了AngularJS是怎样一步一步渲染出一个页面的。那么它又是如何和浏览器的事件回路来交互的呢?或者说是如何跟用户来交互的呢?粗略来说,主要分为三个阶段:
1. 浏览器的事件回路一直等待着事件的触发,事件包括用户的交互操做、定时事件或者网络事件(如服务器的响应等);
2. 一旦有事件触发,就会进入到Javascript的context中,通常经过回调函数来修改DOM;
3. 等到回调函数执行完毕以后,浏览器又根据新的DOM来渲染新的页面。
正以下面一张图所示,交互过程主要由几个循环组成:
AngularJS修改了通常的Javascript工做流,而且提供了它本身的事件处理机制。这样就把Javascript的context分隔成两部分,一部分是原生的Javascript的context,另外一部分是AngularJS的context。只有处在AngularJS的context中的操做才能享受到Angular的data-binding、exception handling、property watching等服务,可是对于外来者(如原生的Javascript操做、自定义的事件回调、第三方的库等)Angular也不是一律不接见,可使用AngularJS提供的$apply()函数将这些外来者包进AngularJS的context中,让Angular感知到他们产生的变化。
接下来,让咱们一块儿来看看交互过程当中的这几个循环是怎么工做的?
1. 首先,浏览器会一直处于监听状态,一旦有事件被触发,就会被加到一个event queue中,event queue中的事件会一个一个的执行。
2. event queue中的事件若是是被$apply()包起来的话,就会进入到AngularJS的context中,这里的fn()是咱们但愿在AngularJS的context中执行的函数。
3. AngularJS将执行fn()函数,一般状况下,这个函数会改变应用的某些状态。
4. 而后AngularJS会进入到由两个小循环组成的$digest循环中,一个循环是用来处理$evalAsync队列(用来schedule一些须要在渲染视图以前处理的操做,一般经过setTimeout(0)实现,速度会比较慢,可能会出现视图抖动的问题)的,一个循环是处理$watch列表(是一些表达式的集合,一旦有改变发生,那么$watch函数就会被调用)的。$digest循环会一直迭代知道$evalAsync队列为空而且$watch列表也为空的时候,即model再也不有任何变化。
5. 一旦AngularJS的$digest循环结束,整个执行就会离开AngularJS和Javascript的context,紧接着浏览器就会把数据改变后的视图从新渲染出来。
接下来,咱们仍是结合代码来解析一下:网络
<!doctype html> <html ng-app> <head> <script src="angular.js"></script> </head> <body> <input ng-model="name"> <p>Hello {{name}}!</p> </body> </html>
这段代码和上一段代码惟一的区别就是有了一个input来接收用户的输入。在用浏览器去访问这个html文件的时候,input上的ng-model指令会给input绑上keydown事件,而且会给name变量建议一个$watch来接收变量值改变的通知。在交互阶段主要会发生如下一系列事件:
1. 当用户按下键盘上的某一个键的时候(好比说A),触发input上的keydown事件;
2. input上的指令察觉到input里值的变化,调用$apply(“name=‘A’”)更新处于AngularJS的context中的model;
3. AngularJS将’A’赋值给name;
4. $digest循环开始,$watch列表检测到name值的变化,而后通知{{name}}表达式,更新DOM;
5. 退出AngularJS的context,而后退出Javascript的context中的keydown事件;
6. 浏览器从新渲染视图。
最后,但愿这篇博客能帮助你们更好的理解AngularJS在背后干的事情。若有不确切的地方,请指正!app