Home > Web Front-end > JS Tutorial > Understanding dirty checking in angularjs

Understanding dirty checking in angularjs

青灯夜游
Release: 2021-02-01 11:45:24
forward
1977 people have browsed it

Understanding dirty checking in angularjs

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;

Introduction to angular.js

  • AngularJs is an mvvm framework, its component is the vm component, and scope is the data collection of the vm component
  • AngularJs declares the behavior of the vm through directive, which is implemented as a watcher, listens for changes in the properties of the scope, and updates the UI with the latest properties
  • Two-way binding of AngularJs: For example: one is to $ The scope attribute value is bound to the HTML structure. When the $scope attribute value changes, the interface also changes. The other is that when the user performs operations on the interface, such as clicking, inputting, and selecting, the $scope attribute is automatically triggered. Changes (the interface may also change)
  • Listen to scope attribute changes: dirty check

Dirty check

  • angular does not listen at all Data changes, but at the right time ($watch), traverse all $scopes starting from $rootScope,
  • Check whether the attribute values ​​​​on them have changed, and if there are changes, use a variable dirty to record it as true, traverse ($digest) again,
  • and so on, until a certain traversal is completed and the attribute values ​​​​of these $scopes have not changed, the traversal ends.
  • Because a dirty variable is used as a record, it is called a dirty check 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:执行深检查
Copy after login
  • After completing the binding, it will automatically detect changes in these properties and execute $watch. Then the corresponding information will be bound to a $$watchers inside angular.
  • It is A queue (array), and when $digest is triggered, angular will traverse the array,
  • and use a dirty variable to record whether the $scope attributes recorded in $$watchers have changed

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

$apply triggers $digest

  • Generally, $digest is not called. Calling $apply will internally trigger $digest recursive traversal.
  • angular’s ​​internal instructions encapsulate $apply, such as ng-click, so there is generally no need to manually call apply

Manually calling apply

  • is sometimes required Manual trigger
function($timeout) {
  // 当我们通过on('click')的方式触发某些更新的时候,可以这样做
  $timeout(() => { // 内置语法糖 $http, $timeout已经包含了apply
    $scope.name = 'lily'
  })
  // 也可以这样做
  $element.on('click', () => {
    $scope.name = 'david'
    $scope.$apply()
  })
}
Copy after login
Note: During the recursive process, $apply must not be called manually, such as in the ng-click function, such as in the callback function of $watch.

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(&#39;$digest&#39;);
      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(&#39;[ng-bind]&#39;);
      console.log(&#39;list&#39;, list)
      for (let i = 0, l = list.length; i < l; i++) {
        let bindData = list[i].getAttribute(&#39;ng-bind&#39;);
        console.log(&#39;bindData&#39;, bindData)
        console.log(&#39;list[i]&#39;, 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(&#39;data&#39;, function(newValue, oldValue) { // 监听
        console.log("new: " + newValue + "=========" + "old: " + oldValue);
    });


    // 手动为button按钮添加onclick事件,并为通过闭包为其绑定了全局scope对象,绑定apply方法
    // 类似angular内部实现
    function startBind() {
      let list = document.querySelectorAll(&#39;[ng-click]&#39;);
      for (let i = 0, l = list.length; i < l; i++) {
        list[i].onclick = (function (index) {
          return function () {
            let func = this.getAttribute(&#39;ng-click&#39;);
            $scope[func]($scope);
            $scope.$digest();
            $scope.$apply()
          }
        })(i)
      }
    }

    // 初始化
    startBind();
  }

</script>

</html>
Copy after login

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!

Related labels:
source:cnblogs.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template