ホームページ  >  記事  >  ウェブフロントエンド  >  angularjs でのダーティ チェックを理解する

angularjs でのダーティ チェックを理解する

青灯夜游
青灯夜游転載
2021-01-20 17:26:301925ブラウズ

angularjs でのダーティ チェックを理解する

関連する推奨事項: 「angularjs チュートリアル

angularjs は双方向バインディングを実装します。これは、vue のdefineProperty とは異なります。その原理は、以下は、ダーティ チェック メカニズムの概要です。

angular.js の概要

  • AngularJs は mvvm フレームワークであり、そのコンポーネントは vm コンポーネントであり、スコープはデータ コレクションです。 vm コンポーネントの
  • AngularJs はディレクティブを通じて vm の動作を宣言します。これはウォッチャーとして実装され、スコープのプロパティの変更をリッスンし、最新のプロパティで UI を更新します
  • AngularJs の双方向バインディング: 例: 1 つは $ にバインドされます。scope 属性値は HTML 構造にバインドされます。$scope 属性値が変更されると、インターフェイスも変更されます。もう 1 つは、ユーザーが HTML 構造に対して操作を実行するときです。インターフェイス (クリック、入力、選択など) を実行すると、$scope 属性が自動的にトリガーされます。ダーティ チェック
  • angular はデータの変更をまったくリッスンしませんが、適切なタイミング ($watch) で、$rootScope から始まるすべての $scope を走査し、

属性値が正しいかどうかを確認します。変更があった場合は、変数 Dirty を使用してそれを true として記録し、再度 ($digest) を走査し、

    というように、特定の走査が完了し、これらの $scope の属性値が変更されていない場合、トラバーサルは終了します。
  • ダーティ変数はレコードとして使用されるため、ダーティ チェック機構と呼ばれます。
  • 要するに: スコープが作成されると、angular はテンプレートを解析し、バインディング値とイベント呼び出しを見つけて、それらを $watch;
  • # でバインドします。 ##
    $scope.$watch(string|function, listener, objectEquality, prettyPrintExpression)
    // string: 验证值或者function执行后return的string
    // listener: 如果验证值不同,则执行该监听函数
    // objectEquality:执行深检查
バインディングが完了すると、これらのプロパティの変更が自動的に検出され、$watch が実行され、対応する情報が angular 内の $$watchers にバインドされます。キュー (配列)、$digest がトリガーされると、angular は配列

を走査し、ダーティ変数を使用して $$watchers

# に記録された $scope 属性に変更があるかどうかを記録します。
##次の処理:
  • dirty が true かどうかを判定し、false の場合、$digest 再帰は実行されません。 (dirty のデフォルトは true)
$$watchers をトラバースし、対応する属性値の古い値と新しい値を取り出し、objectEquality に従って古い値と新しい値を比較します。

  • 2 つの値が異なる場合は、実行を続行します。 2 つの値が同じ場合は、dirty を false に設定します。

  • すべてのウォッチャーをチェックした後、dirty がまだ true である場合は、dirty を true に設定し、古い値を新しい値に置き換えます。

  • Inこのようにして、次の再帰ラウンドでは、古い値がこのラウンドの新しい値となり、$digest を再度呼び出します (簡単に言えば、2 回の再帰走査を実行して、古い値と新しい値の変化を確認することです)

  • 変更された値 $scope がインターフェイスに再レンダリングされます

  • $apply が $digest をトリガーします

  • 通常、$digest $apply を呼び出すと、内部で $digest 再帰トラバーサルがトリガーされます。
  • angular の内部命令は、ng-click などの $apply をカプセル化するため、通常は apply を手動で呼び出す必要はありません

apply の手動呼び出しが必要になる場合があります。手動トリガー

function($timeout) {
  // 当我们通过on('click')的方式触发某些更新的时候,可以这样做
  $timeout(() => { // 内置语法糖 $http, $timeout已经包含了apply
    $scope.name = 'lily'
  })
  // 也可以这样做
  $element.on('click', () => {
    $scope.name = 'david'
    $scope.$apply()
  })
}
    注: 再帰プロセス中は、次のように $apply を手動で呼び出してはいけません。 $watch のコールバック関数などの ng-click 関数。
  • 最後に、単純なダーティ チェック メカニズムを実装します
  • <!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>
  • プログラミング関連の知識の詳細については、
プログラミング ビデオ

をご覧ください。 !

以上がangularjs でのダーティ チェックを理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcnblogs.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。