搜尋
首頁web前端js教程AngularJS雙向資料綁定原理(詳細教學)

AngularJS雙向資料綁定原理(詳細教學)

Jun 08, 2018 pm 05:57 PM
$watchangularjs

這篇文章主要介紹了AngularJS雙向資料綁定原理之$watch、$apply和$digest的應用,具有一定的參考價值,有興趣的小夥伴們可以參考一下

引子

這篇文章是寫給AngularJS新手的,如果你已經對AngularJS的雙向資料綁定有了深入的了解,直接去閱讀原始碼好了。

背景

AngularJS開發者都想知道雙向資料綁定是怎麼實現的。與data-binding相關的術語琳瑯滿目: $watch,$apply,$digest,dirty-checking等等它們是如何運作的呢?讓我們從頭開始講起吧

AngularJS 的雙向資料綁定是被瀏覽器逼的

瀏覽器看上去很美,其實在資料互動這塊兒,由於瀏覽器的“不作為”,導致瀏覽器的資料刷新成為一個難題。具體來說,瀏覽器可以輕鬆監聽一個事件,例如:使用者點擊一個按鈕,或是在輸入框裡輸入東西,為此還提供了事件回調函數的API,事件的回調函數就會在javascript解釋器裡執行;但反過來就沒這麼簡單了,如果來自後台的數據發生了變化,需要通知給瀏覽器,讓瀏覽器刷新,瀏覽器並沒有提供這樣的數據交互機制,對於開發者來說,這是一個難以克服的障礙,該怎麼辦呢? AngularJS出現了,它透過$scope 很好地實現了雙向資料綁定,背後的原理就是$watch,$apply,$digest,dirty-checking

##$watch 佇列($watch list)

從字面上看,watch 是觀察的意思。每次將東西綁定到瀏覽器時,就會往$watch佇列插入一張$watch。想像一下$watch就是那個可以偵測它監視的model裡時候有變化的東西。例如你有如下的程式碼

User: <input type="text" ng-model="user" />
Password: <input type="password" ng-model="pass" />

這裡有個$scope.user,它被綁定在了第一個輸入框上,還有個$scope.pass,它被綁定在了第二個輸入框上;然後在$watch list裡面加入兩個$watch:

建立一個controllers.js 文件,程式碼如下:

app.controller(&#39;MainCtrl&#39;, function($scope) {
 $scope.foo = "Foo";
 $scope.world = "World";
});

對應的html 檔案, index.html 程式碼如下:

Hello, {{ World }}

這裡,即使在$scope上添加了兩個東西,但是只有一個綁定在了UI上,因此只生成了一個$watch. 再看下面的例子:

controllers.js

app.controller(&#39;MainCtrl&#39;, function($scope) {
 $scope.people = [...];
});

對應的html檔index.html

<ul>
 <li ng-repeat="person in people">
   {{person.name}} - {{person.age}}
 </li>
</ul>

#這樣看來,又產生了多個$watch。每個person有兩個(一個name,一個age),然後ng-repeat是一個循環,因此10個person一共是(2 * 10) 1,也就是說有21個$watch。因此,每一個綁定到了瀏覽器上的資料都會產生一個$watch。對,那這寫$watch是什麼時候產生的呢?先回顧下AngularJS的載入原理

AngularJS的載入原理:

AngularJS的範本載入分為編譯(compile)和連結(linking)兩個階段,在linking階段,AngularJS解譯器會尋找每個directive,然後產生每個需要的$watch。對了,$watch就是在這個階段生成的。

接下來,開始用到$digest了

$digest 循環

從字面上看,digest是「消化」的意思,總感覺這個名字怪怪的,跟不可思議的是dirty-checking, 字面意思“髒檢查”,還是不翻譯為好。原作者的本意絕對不是這個意思,只可意會不可言傳!

$digest 是一個循環,它在循環做什麼呢? $digest 在遍歷我們的$watch。 $digest 一個個問$watch —— 「嗨,你觀察的資料改變了沒?」

這個遍歷就是所謂的dirty-checking。既然所有的$watch都檢查完了,那就要問了:有沒有$watch更新過?如果有至少一個更新過,這個循環就會再次觸發,直到所有的$watch都沒有變化。這樣就能夠保證每個model都已經不會再改變。記住如果循環超過10次的話,它將會拋出一個異常,以免出現無限循環。當$digest循環結束時,DOM會相應地變化。

看段程式碼,例如: controllers.js

app.controller(&#39;MainCtrl&#39;, function() {
 $scope.name = "Foo";
 $scope.changeFoo = function() {
   $scope.name = "Bar";
 }
});

對應的html文件,index.html

{{ name }}
<button ng-click="changeFoo()">Change the name</button>

這裡只有一個$watch,因為ng-click不產生$ watch(函數是不會變的)。

$digest 執行的流程是:

  1. 在瀏覽器按下按鈕;

  2. 瀏覽器接收到一個事件,進入angular context。

  3. $digest循環開始執行,查詢每個$watch是否有變化。

  4. 由於監視$scope.name的$watch報告了變化,它會強制再執行一次$digest循環。

  5. 新的$digest循環沒有偵測到變化,此時瀏覽器拿回控制權,更新與$scope.name新值對應部分的DOM。

從中可以看出AngularJS的一個明顯的不足:每一個進入angular context的事件都會執行一個$digest循環,哪怕僅僅是輸入一個字母,$digest 都會遍歷整個頁面的所有$watch。

$apply 的應用程式

Angular context 是整个Angular的上下文,也可以把它理解为Angular容器,那么,是谁来决定哪些事件可以进入 Angular Context,哪些事件又不能进入呢? 其控制器在 $apply手上。

如果当事件触发时,调用$apply,它会进入angular context,如果没有调用就不会进入。你可能会问:刚才的例子并没有调用$apply,这是怎么回事呢?原来,是Angular背后替你做了。当点击带有ng-click的元素时,事件就会被封装到一个$apply调用中。如果有一个ng-model="foo"的输入框,当输入一个字母 f 时,事件就会这样调用,$apply("foo = 'f';")。

$apply的应用场景

$apply是$scope的一个函数,调用它会强制一次$digest循环。如果当前正在执行$apply循环,则会抛出一个异常。

如果浏览器上数据没有及时刷新,可以通过调用$scope.$apply() 方法,强行刷新一遍。

通过 $watch 监控自己的$scope

<!DOCTYPE html>
<html ng-app="demoApp">
<head>
 <title>test</title>
 <!-- Vendor libraries -->
  <script src="lib/jquery-v1.11.1.js"></script>
  <script src="lib/angular-v1.2.22.js"></script>
  <script src="lib/angular-route-v1.2.22.js"></script>
</head>
<body> 
 <p ng-controller="MainCtrl" >
  <input ng-model="name" />
  Name updated: {{updated}} times.
 </p> 
 <script >
  var demoApp = angular.module(&#39;demoApp&#39;,[]); 
  demoApp.controller(&#39;MainCtrl&#39;, function($scope) {
  $scope.name = "Angular";
  $scope.updated = -1;
  $scope.$watch(&#39;name&#39;, function() {
  $scope.updated++;
 });
});
 </script>
 </body>
</html>

代码说明:

当controller 执行到 $watch时,它会立即调用一次,所以把updated的值设为 -1 。 上输入框中输入字符发生变化时,你会看到 updated 的值随之变化,而且能显示变化的次数。

$watch 检测到的数据变化

小结

我们对 AngularJS的双向数据绑定有了一个初步的认识,对于AngularJS来说,表面上看操作DOM很简单,其实背后有 $watch、$digest 、 $apply 三者在默默地起着作用。这个遍历检查数据是否发生变化的过程,称之为:dirty-checking。 当你了解了这个过程后,你会对它嗤之以鼻,感觉这种方法好low 哦。 确实,如果一个DOM中有 2000- 3000个 watch,页面的渲染速度将会大打折扣。

这个渲染的性能问题怎么解决呢?随着ECMAScript6的到来,Angular 2 通过Object.observe 极大地改善$digest循环的速度。或许,这就是为什么 Angular 团队迫不及待地推出 Angular 2 的原因吧。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在vue-cli中如何配置babel配置文件

使用node.js实现抖音自动抢红包功能

使用webpack打包处理bundle.js文件过大的问题

以上是AngularJS雙向資料綁定原理(詳細教學)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
JavaScript數據類型:瀏覽器和nodejs之間是否有區別?JavaScript數據類型:瀏覽器和nodejs之間是否有區別?May 14, 2025 am 12:15 AM

JavaScript核心數據類型在瀏覽器和Node.js中一致,但處理方式和額外類型有所不同。 1)全局對像在瀏覽器中為window,在Node.js中為global。 2)Node.js獨有Buffer對象,用於處理二進制數據。 3)性能和時間處理在兩者間也有差異,需根據環境調整代碼。

JavaScript評論:使用//和 / * * / * / * /JavaScript評論:使用//和 / * * / * / * /May 13, 2025 pm 03:49 PM

JavaScriptusestwotypesofcomments:single-line(//)andmulti-line(//).1)Use//forquicknotesorsingle-lineexplanations.2)Use//forlongerexplanationsorcommentingoutblocksofcode.Commentsshouldexplainthe'why',notthe'what',andbeplacedabovetherelevantcodeforclari

Python vs. JavaScript:開發人員的比較分析Python vs. JavaScript:開發人員的比較分析May 09, 2025 am 12:22 AM

Python和JavaScript的主要區別在於類型系統和應用場景。 1.Python使用動態類型,適合科學計算和數據分析。 2.JavaScript採用弱類型,廣泛用於前端和全棧開發。兩者在異步編程和性能優化上各有優勢,選擇時應根據項目需求決定。

Python vs. JavaScript:選擇合適的工具Python vs. JavaScript:選擇合適的工具May 08, 2025 am 12:10 AM

選擇Python還是JavaScript取決於項目類型:1)數據科學和自動化任務選擇Python;2)前端和全棧開發選擇JavaScript。 Python因其在數據處理和自動化方面的強大庫而備受青睞,而JavaScript則因其在網頁交互和全棧開發中的優勢而不可或缺。

Python和JavaScript:了解每個的優勢Python和JavaScript:了解每個的優勢May 06, 2025 am 12:15 AM

Python和JavaScript各有優勢,選擇取決於項目需求和個人偏好。 1.Python易學,語法簡潔,適用於數據科學和後端開發,但執行速度較慢。 2.JavaScript在前端開發中無處不在,異步編程能力強,Node.js使其適用於全棧開發,但語法可能複雜且易出錯。

JavaScript的核心:它是在C還是C上構建的?JavaScript的核心:它是在C還是C上構建的?May 05, 2025 am 12:07 AM

javascriptisnotbuiltoncorc; sanInterpretedlanguagethatrunsonenginesoftenwritteninc.1)JavascriptwasdesignedAsignedAsalightWeight,drackendedlanguageforwebbrowsers.2)Enginesevolvedfromsimpleterterpretpretpretpretpreterterpretpretpretpretpretpretpretpretpretcompilerers,典型地,替代品。

JavaScript應用程序:從前端到後端JavaScript應用程序:從前端到後端May 04, 2025 am 12:12 AM

JavaScript可用於前端和後端開發。前端通過DOM操作增強用戶體驗,後端通過Node.js處理服務器任務。 1.前端示例:改變網頁文本內容。 2.後端示例:創建Node.js服務器。

Python vs. JavaScript:您應該學到哪種語言?Python vs. JavaScript:您應該學到哪種語言?May 03, 2025 am 12:10 AM

選擇Python還是JavaScript應基於職業發展、學習曲線和生態系統:1)職業發展:Python適合數據科學和後端開發,JavaScript適合前端和全棧開發。 2)學習曲線:Python語法簡潔,適合初學者;JavaScript語法靈活。 3)生態系統:Python有豐富的科學計算庫,JavaScript有強大的前端框架。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境