我的以爲,要很好的理解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