這篇文章主要介紹了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('MainCtrl', function($scope) { $scope.foo = "Foo"; $scope.world = "World"; });對應的html 檔案, index.html 程式碼如下:
Hello, {{ World }}這裡,即使在$scope上添加了兩個東西,但是只有一個綁定在了UI上,因此只生成了一個$watch. 再看下面的例子:controllers.js
app.controller('MainCtrl', 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.jsapp.controller('MainCtrl', 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 執行的流程是:
- 在瀏覽器按下按鈕;
- 瀏覽器接收到一個事件,進入angular context。
- $digest循環開始執行,查詢每個$watch是否有變化。
- 由於監視$scope.name的$watch報告了變化,它會強制再執行一次$digest循環。
- 新的$digest循環沒有偵測到變化,此時瀏覽器拿回控制權,更新與$scope.name新值對應部分的DOM。
$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('demoApp',[]); demoApp.controller('MainCtrl', function($scope) { $scope.name = "Angular"; $scope.updated = -1; $scope.$watch('name', 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 的原因吧。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
以上是AngularJS雙向資料綁定原理(詳細教學)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

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

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)