搜尋
首頁web前端js教程了解angularjs中的髒檢查

了解angularjs中的髒檢查

Jan 20, 2021 pm 05:26 PM
angularjs

了解angularjs中的髒檢查

相關推薦:《angularjs教學

angularjs實作了雙向綁定,與vue的defineProperty不同,它的原理在於它的髒檢查機制,以下做了一些總結;

angular.js介紹

  • AngularJs是mvvm框架,它的元件是vm元件,scope是vm元件的資料集合
  • AngularJs透過directive來宣告vm的行為,它實作為一個watcher,監聽scope的屬性的變化,把最新的屬性更新UI
  • AngularJs的雙向綁定:如:一個是將$ scope屬性值綁定到HTML結構中,當$scope屬性值改變的時候介面也會改變;另一個是,當使用者在介面上進行操作,例如點擊、輸入、選擇時,自動觸發$scope屬性的變化(介面也可能跟著變)
  • 監聽scope的屬性變更:髒檢查(dirty check )

髒檢查

    ##angular根本不監聽資料的變動,而是在適當的時機($watch)從$rootScope開始遍歷所有$scope,
  • 檢查它們上面的屬性值是否有變化,如果有變化,就用一個變數dirty記錄為true,再次進行遍歷($digest),
  • 如此往復,直到某一個遍歷完成時,這些$scope的屬性值都沒有變化時,結束遍歷。
  • 由於使用了一個dirty變數作為記錄,因此稱為髒檢查機制。
簡而言之: 當作用域建立時,angular會去解析模板,將綁定值和事件呼叫找出來並用$watch綁定;

$scope.$watch(string|function, listener, objectEquality, prettyPrintExpression)
// string: 验证值或者function执行后return的string
// listener: 如果验证值不同,则执行该监听函数
// objectEquality:执行深检查
    完成綁定後,就會自動檢測這些屬性的變化,執行$watch, 那麼對應的資訊被綁定到angular內部的一個$$watchers中,
  • 它是一個佇列(數組),而當$digest被觸發時,angular就會去遍歷這個數組,
  • 並且用一個dirty變數記錄$$watchers裡面記錄的那些$scope屬性是否有變化
接下來的流程:

  • 判斷dirty是否為true,如果為false,則不進行$digest遞迴。 (dirty預設為true)

  • 遍歷$$watchers,取出對應的屬性值的老值和新值根據objectEquality進行新舊值的比較。

  • 如果兩個值不同,則繼續往下執行。如果兩個值相同,則設定dirty為false。

  • 檢查完所有的watcher之後,如果dirty還為true, 設定dirty為true用新值取代老值;

  • 這樣,在下一輪遞歸的時候,老值就是這一輪的新值再次調用$digest(簡單說就是執行兩次遞歸遍歷檢查新舊值變化)

  • 將變化後的$scope重新渲染到介面

$apply觸發$digest

    一般不呼叫$digest, 呼叫$apply,它內部會觸發$digest遞歸遍歷
  • angular的內部指令封裝了$apply,例如ng-click,所以一般不用手動呼叫apply
手動呼叫apply

    部分時候需要手動觸發
  • function($timeout) {
      // 当我们通过on('click')的方式触发某些更新的时候,可以这样做
      $timeout(() => { // 内置语法糖 $http, $timeout已经包含了apply
        $scope.name = 'lily'
      })
      // 也可以这样做
      $element.on('click', () => {
        $scope.name = 'david'
        $scope.$apply()
      })
    }
注意:在遞歸過程中,絕對不能手動呼叫$apply,例如在ng-click的函數中,例如在$watch的回呼函數中。
最後,實作一個簡易髒檢查機制

<!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中文網其他相關文章!

陳述
本文轉載於:博客园。如有侵權,請聯絡admin@php.cn刪除
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有強大的前端框架。

JavaScript框架:為現代網絡開發提供動力JavaScript框架:為現代網絡開發提供動力May 02, 2025 am 12:04 AM

JavaScript框架的強大之處在於簡化開發、提升用戶體驗和應用性能。選擇框架時應考慮:1.項目規模和復雜度,2.團隊經驗,3.生態系統和社區支持。

JavaScript,C和瀏覽器之間的關係JavaScript,C和瀏覽器之間的關係May 01, 2025 am 12:06 AM

引言我知道你可能會覺得奇怪,JavaScript、C 和瀏覽器之間到底有什麼關係?它們之間看似毫無關聯,但實際上,它們在現代網絡開發中扮演著非常重要的角色。今天我們就來深入探討一下這三者之間的緊密聯繫。通過這篇文章,你將了解到JavaScript如何在瀏覽器中運行,C 在瀏覽器引擎中的作用,以及它們如何共同推動網頁的渲染和交互。 JavaScript與瀏覽器的關係我們都知道,JavaScript是前端開發的核心語言,它直接在瀏覽器中運行,讓網頁變得生動有趣。你是否曾經想過,為什麼JavaScr

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

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

熱門文章

熱工具

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境