Related recommendations: "angularjs Tutorial"
angularjs implements two-way binding, which is different from vue's defineProperty. Its principle lies in its The following is a summary of the dirty checking mechanism;
In short: When the scope is created, angular will parse the template, find out the binding values and event calls and bind them with $watch;
$scope.$watch(string|function, listener, objectEquality, prettyPrintExpression) // string: 验证值或者function执行后return的string // listener: 如果验证值不同,则执行该监听函数 // objectEquality:执行深检查
Next process:
Determine whether dirty is true. If it is false, $digest recursion will not be performed. (dirty defaults to true)
Traverse $$watchers, take out the old value and new value of the corresponding attribute value, and compare the old and new values according to objectEquality.
If the two values are different, continue execution. If the two values are the same, set dirty to false.
After checking all watchers, if dirty is still true, set dirty to true and replace the old value with the new value;
In this way, In the next round of recursion, the old value is the new value of this round and call $digest again (simply speaking, it is to perform two recursive traversals to check the changes of the old and new values)
The changed value $scope re-renders to the interface
function($timeout) { // 当我们通过on('click')的方式触发某些更新的时候,可以这样做 $timeout(() => { // 内置语法糖 $http, $timeout已经包含了apply $scope.name = 'lily' }) // 也可以这样做 $element.on('click', () => { $scope.name = 'david' $scope.$apply() }) }
Finally, implement a simple dirty checking mechanism
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>angularjs脏检查实现</title> </head> <style type="text/css"> button { height: 60px; width: 100px; } p { margin-left: 20px; } </style> <body> <div> <button type="button" ng-click="increase">增加</button> <button type="button" ng-click="decrease">减少</button> 数量:<span ng-bind="data">0</span> </div> <br> </body> <script> window.onload = function () { /** * 声明构造函数 */ function Scope() { this.$$watchList = []; // angular内部会声明一个数组(包含监听的对象),在digest执行时去遍历 } /** * 属性赋值给$scope * 类似angular解析controller的模板,把模板中的属性解析出来,属性赋值给$scope */ Scope.prototype.getNewValue = function () { return $scope[this.name]; } /** * 实现监听 */ Scope.prototype.$watch = function (name, listener) { let watch = { name: name, getNewValue: this.getNewValue, listener: listener || function () { } }; // 当作用域创建时,angular会去解析模板,$watch用来绑定监听值和监听函数 this.$$watchList.push(watch); } /** * 检查dirty,循环更新scope上的最新值 */ Scope.prototype.$digest = function () { console.log('$digest'); let dirty = true; // 默认dirty变量为true let checkTimes = 0; while (dirty) { dirty = this.$valScope(); checkTimes++; if (checkTimes > 10 && dirty) { throw new Error("循环过多"); } } } /** * 验证值是否有变化 */ Scope.prototype.$valScope = function () { let dirty; let list = this.$$watchList; for (let i = 0; i < list.length; i++) { let watch = list[i]; let newValue = watch.getNewValue(); let oldValue = watch.last || undefined; if (newValue !== oldValue) { watch.listener(newValue, oldValue); dirty = true; // 如果新旧值不同,则继续遍历 } else { dirty = false; } watch.last = newValue; } return dirty; } /** * 刷新scope */ Scope.prototype.$apply = function (params) { let list = document.querySelectorAll('[ng-bind]'); console.log('list', list) for (let i = 0, l = list.length; i < l; i++) { let bindData = list[i].getAttribute('ng-bind'); console.log('bindData', bindData) console.log('list[i]', list[i]) list[i].innerHTML = $scope[bindData]; } } let $scope = new Scope(); // 实例化,声明$scope对象集合 $scope.data = 0; $scope.increase = function () { this.data++; }; $scope.decrease = function () { this.data--; }; $scope.$watch('data', function(newValue, oldValue) { // 监听 console.log("new: " + newValue + "=========" + "old: " + oldValue); }); // 手动为button按钮添加onclick事件,并为通过闭包为其绑定了全局scope对象,绑定apply方法 // 类似angular内部实现 function startBind() { let list = document.querySelectorAll('[ng-click]'); for (let i = 0, l = list.length; i < l; i++) { list[i].onclick = (function (index) { return function () { let func = this.getAttribute('ng-click'); $scope[func]($scope); $scope.$digest(); $scope.$apply() } })(i) } } // 初始化 startBind(); } </script> </html>
For more programming-related knowledge, please visit: Programming Video! !
The above is the detailed content of Understanding dirty checking in angularjs. For more information, please follow other related articles on the PHP Chinese website!