วิธีการแก้ไขข้อผิดพลาด "การทำซ้ำ 10 $ Digest () ถึง" เชิงมุม


92

ถึงการทำซ้ำ 10 $ Digest () แล้ว แท้ง!

มีข้อความสนับสนุนจำนวนมากในความหมายของ "ผู้เฝ้าดูยิงในการทำซ้ำ 5 ครั้งล่าสุด:" ฯลฯ แต่ข้อความส่วนใหญ่นี้เป็นโค้ด Javascript จากฟังก์ชันต่างๆ มีกฎง่ายๆในการวินิจฉัยปัญหานี้หรือไม่? เป็นปัญหาที่สามารถบรรเทาได้เสมอหรือมีแอปพลิเคชันที่ซับซ้อนเพียงพอที่จะถือว่าปัญหานี้เป็นเพียงคำเตือนหรือไม่?

คำตอบ:


81

ดังที่ Ven กล่าวว่าคุณกำลังส่งคืนวัตถุที่แตกต่างกัน (ไม่เหมือนกัน) ในแต่ละ$digestรอบหรือคุณกำลังแก้ไขข้อมูลหลายครั้งเกินไป

วิธีแก้ปัญหาที่เร็วที่สุดในการค้นหาว่าส่วนใดของแอปที่ทำให้เกิดพฤติกรรมนี้คือ

  1. ลบ HTML ที่น่าสงสัยทั้งหมด - โดยทั่วไปแล้วจะลบ html ของคุณออกจากเทมเพลตและตรวจสอบว่าไม่มีคำเตือนหรือไม่
  2. หากไม่มีคำเตือนให้เพิ่มส่วนเล็ก ๆ ของ html ที่คุณลบออกและตรวจสอบว่าปัญหากลับมาหรือไม่
  3. ทำซ้ำขั้นตอนที่ 2 จนกว่าคุณจะได้รับคำเตือน - คุณจะทราบว่าส่วนใดของ html ที่รับผิดชอบปัญหา
  4. ตรวจสอบเพิ่มเติม - ส่วนจากขั้นตอนที่ 3 มีหน้าที่ในการกลายพันธุ์วัตถุบน$scopeหรือส่งคืนวัตถุที่ไม่เหมือนกันในแต่ละ$digestรอบ
  5. หากคุณยังคงมี$digestคำเตือนการทำซ้ำหลังจากขั้นตอนที่ 1 แสดงว่าคุณอาจกำลังทำสิ่งที่น่าสงสัยอยู่มาก ทำซ้ำขั้นตอนเดียวกันสำหรับแม่แบบ / ขอบเขต / ตัวควบคุมหลัก

คุณต้องแน่ใจด้วยว่าคุณไม่ได้เปลี่ยนอินพุตของตัวกรองที่กำหนดเองของคุณ

โปรดทราบว่าใน JavaScript มีวัตถุบางประเภทที่ไม่ทำงานอย่างที่คุณคาดหวังตามปกติ:

new Boolean(true) === new Boolean(true) // false
new Date(0) == new Date(0) // false
new String('a') == new String('a') // false
new Number(1) == new Number(1) // false
[] == [] // false
new Array == new Array // false
({})==({}) // false

5
ขอขอบคุณ! นี่คือฮิวริสติกที่เป็นประโยชน์ ฉันยังคิดว่าฟีเจอร์ "track by" ใหม่ของ Angular สำหรับ ngRepeat จะช่วยฉันได้เช่นกัน ฉันกำลังทำแผนที่ () และ groupBy () บางอย่างโดยใช้ขีดล่างในบริการดังนั้นจึงส่งคืนอ็อบเจ็กต์ "ที่แตกต่างกัน" ทุกครั้ง (แม้ว่าจะแสดงถึงสิ่งเดียวกันอย่างมีเหตุผล - "track by Id" จะช่วยไม่ให้ Angular มองเห็น เป็น "การเปลี่ยนแปลง" หากยังไม่เกิดขึ้นจริง)
บลาสเตอร์

2
หากคุณกำลังทำmap()และตรวจสอบgroupBy()ให้แน่ใจว่า$watches ของคุณทำการตรวจสอบสิ่งสกปรกโดยobjectEquality $watch('myFunctionDoingGropby',callback,true) ดูที่docs.angularjs.org/api/ng.$rootScope.Scope#$watch
g00fy

ตามความคิดเห็นด้านบน "ติดตามโดย" แก้ไขปัญหาของฉัน (ดูเอกสารที่นี่: docs.angularjs.org/api/ng/directive/ngRepeat ) ฉันจะขอบคุณสำหรับความคิดเห็นที่อธิบายว่าทำไมถึงได้ผล ...
Soferio

@ g00fy: นั่นเป็นโอกาสในการขายที่ดีและฉันสามารถแทนที่ฟังก์ชันการดึงรายการของฉันด้วยตัวแปรบนของฉัน$scopeที่ได้รับการกำหนด_.mapรายการ -ed เพียงครั้งเดียว - แต่ในกรณีทั่วไปคุณจะมีอิทธิพลอย่างไรกับการตรวจสอบสกปรกตามความเท่าเทียมกันของวัตถุหาก ไม่ใช่สิ่งที่สร้างขึ้นด้วยตนเอง$watchที่สะดุด แต่ngRepeat?
หรือผู้ทำแผนที่

73

โดยปกติจะเกิดขึ้นเมื่อคุณส่งคืนวัตถุอื่นทุกครั้ง

ตัวอย่างเช่นหากคุณใช้สิ่งนี้ในng-repeat:

$scope.getObj = function () {
  return [{a: 1}, {b: 2}];
};

คุณจะได้รับข้อความแสดงข้อผิดพลาดนี้เนื่องจาก Angular พยายามที่จะมี "ความเสถียร" และจะเรียกใช้ฟังก์ชันจนกว่าจะส่งคืนผลลัพธ์เดียวกัน 2 ครั้ง (เปรียบเทียบกับ===) ซึ่งในกรณีของเราจะไม่คืนค่าจริงเนื่องจากฟังก์ชันจะส่งกลับค่า วัตถุใหม่

console.log({} === {}); // false. Those are two different objects!

ในกรณีนี้คุณสามารถแก้ไขได้โดยจัดเก็บวัตถุไว้ในขอบเขตโดยตรงเช่น

$scope.objData = [{a: 1}, {b: 2}];
$scope.getObj = function () {
  return $scope.objData;
};

ด้วยวิธีนี้คุณจะส่งคืนวัตถุเดิมเสมอ!

console.log($scope.objData === $scope.objData); // true (a bit obvious...)

(คุณไม่ควรพบสิ่งนั้นแม้ในแอปพลิเคชันที่ซับซ้อน)

ปรับปรุง: เชิงมุมได้เพิ่มบางคำอธิบายเพิ่มเติมในเชิงลึกเกี่ยวกับเว็บไซต์ของพวกเขา


คุณจะหยุดไม่ให้สิ่งนี้เกิดขึ้นได้อย่างไร? ตอนนี้ฉันมีสถานการณ์คล้าย ๆ กัน
ผู้พิชิต

2
ตรวจสอบให้แน่ใจว่าคุณไม่ได้สร้างวัตถุที่แตกต่างกันในการโทรแต่ละครั้ง;)
Ven

ฉันจะมั่นใจได้อย่างไร? ฉันกำลังทำบางสิ่งบางอย่างเช่น item ใน func (obj) แต่ดูเหมือนว่า func จะถูกเรียกหลายครั้งแทนที่จะเป็นครั้งเดียวอย่างที่หวัง ฉันพยายามใช้ ng-init เพื่อเรียก func จากนั้นแนบเข้ากับโมเดลในขอบเขต แต่ก็ไม่ได้ผลเช่นกัน
ผู้พิชิต

1
นี่คือตัวอย่างที่คุณเห็นทุกที่เกี่ยวกับปัญหานี้ มันจะน่ากลัวดังนั้นหากเชิงมุมสามารถชี้ไปที่ฟังก์ชั่นที่กระทำผิดที่มีลักษณะการทำงานนี้ ...
Jorn

1
@BenWheeler มันดีขึ้นอย่างแน่นอนตั้งแต่ปี 2013 ใช่: P.
Ven

11

แค่อยากจะโยนวิธีแก้ปัญหานี้ไว้ที่นี่หวังว่ามันจะช่วยคนอื่นได้ ฉันได้รับปัญหาการวนซ้ำนี้เนื่องจากฉันกำลังทำซ้ำในคุณสมบัติที่สร้างขึ้นซึ่งกำลังสร้างวัตถุใหม่ทุกครั้งที่มีการเรียกใช้

ฉันแก้ไขโดยแคชอ็อบเจ็กต์ที่สร้างขึ้นในครั้งแรกที่มีการร้องขอจากนั้นจะคืนแคชหากมีอยู่เสมอ ยังเพิ่มเมธอด dirty () ซึ่งจะทำลายผลลัพธ์ที่แคชไว้ตามต้องการ

ฉันมีสิ่งนี้:

function MyObj() {
    var myObj = this;
    Object.defineProperty(myObj, "computedProperty" {
        get: function () {
            var retObj = {};

            return retObj;
        }
    });
}

และนี่คือโซลูชันที่ดำเนินการ:

function MyObj() {
    var myObj = this,
        _cached;
    Object.defineProperty(myObj, "computedProperty" {
        get: function () {
            if ( !_cached ) {
                _cached = {};
            }

            return _cached;
        }
    });

    myObj.dirty = function () {
        _cached = null;
    }
}

โอ้พระเจ้าฉันหวังว่าฉันจะให้คะแนนโหวต 10 คะแนน คุณเพิ่งแก้ปัญหาที่ทำให้ฉันเอาหัวโขกกำแพงเกือบ 3 ชั่วโมง ฉันรักคุณ!
ย่า

7

นอกจากนี้ยังมีความเป็นไปได้ที่มันจะไม่วนซ้ำไม่สิ้นสุดเลย การทำซ้ำ 10 ครั้งไม่ใช่จำนวนที่มากพอที่จะสรุปได้ว่าด้วยจำนวนที่แน่นอน ดังนั้นก่อนที่จะไล่ล่าห่านป่าขอแนะนำให้แยกแยะความเป็นไปได้นั้นก่อน

วิธีที่ง่ายที่สุดคือการเพิ่มจำนวนลูปการย่อยสูงสุดให้เป็นจำนวนที่มากขึ้นซึ่งสามารถทำได้ในmodule.configวิธีนี้โดยใช้$rootScopeProvider.digestTtl(limit)วิธีการ หากinfdigข้อผิดพลาดไม่ปรากฏขึ้นอีกต่อไปคุณก็มีตรรกะการอัพเดตที่ซับซ้อนเพียงพอ

ถ้าคุณสร้างข้อมูลหรือวิวอาศัยนาฬิกา recursive คุณอาจต้องการที่จะค้นหาสำหรับการแก้ปัญหาซ้ำ (เช่นไม่อาศัยใหม่แยกแยะลูปที่จะเริ่มต้น) โดยใช้while, หรือfor Array.forEachบางครั้งโครงสร้างจะซ้อนกันสูงและไม่ได้วนซ้ำอีกด้วยอาจจะไม่มีอะไรให้ทำมากนักในกรณีเหล่านั้นยกเว้นการเพิ่มขีด จำกัด

อีกวิธีหนึ่งในการแก้ไขข้อผิดพลาดคือการดูข้อมูลสรุป ถ้าคุณพิมพ์ JSON สวย ๆ คุณจะได้อาร์เรย์อาร์เรย์ รายการระดับบนสุดแต่ละรายการแสดงถึงการวนซ้ำการทำซ้ำแต่ละรายการประกอบด้วยรายการเฝ้าดู

ตัวอย่างเช่นหากคุณมีคุณสมบัติที่แก้ไขใน$watchตัวมันเองจะเห็นได้ง่ายว่าค่านั้นเปลี่ยนแปลงไปเรื่อย ๆ :

$scope.vm.value1 = true;
$scope.$watch("vm.value1", function(newValue)
{
    $scope.vm.value1 = !newValue;
});
[
   [
      {
         "msg":"vm.value1",
         "newVal":true,
         "oldVal":false
      }
   ],
   [
      {
         "msg":"vm.value1",
         "newVal":false,
         "oldVal":true
      }
   ],
   [
      {
         "msg":"vm.value1",
         "newVal":true,
         "oldVal":false
      }
   ],
   [
      {
         "msg":"vm.value1",
         "newVal":false,
         "oldVal":true
      }
   ],
   [
      {
         "msg":"vm.value1",
         "newVal":true,
         "oldVal":false
      }
   ]
]

แน่นอนว่าในโปรเจ็กต์ขนาดใหญ่สิ่งนี้อาจไม่ง่ายอย่างที่คิดโดยเฉพาะอย่างยิ่งเนื่องจากmsgฟิลด์มักมีค่า"fn: regularInterceptedExpression"หากนาฬิกาเป็นแบบ{{ }}สอดแทรก

นอกเหนือจากนั้นวิธีการที่กล่าวไปแล้วเช่นการตัด HTML เพื่อค้นหาต้นตอของปัญหาก็มีประโยชน์แน่นอน


6

ฉันมีปัญหาเดียวกัน - ฉันสร้างวันที่ใหม่ทุกครั้ง ดังนั้นสำหรับทุกคนที่เกี่ยวข้องกับวันที่ฉันแปลงสายทั้งหมดเช่นนี้:

var date = new Date(); // typeof returns object

ถึง:

var date = new Date().getTime(); // typeof returns number

การเริ่มต้นตัวเลขแทนออบเจ็กต์วันที่ช่วยแก้ปัญหาให้ฉัน


2

วิธีง่ายๆคือใช้ angular.js ไม่ใช่ไฟล์ min เปิดและค้นหาบรรทัด:

if ((dirty || asyncQueue.length) && !(ttl--)) {

แอดไลน์ด้านล่าง:

console.log("aaaa",watch)

จากนั้นรีเฟรชหน้าของคุณในคอนโซลเครื่องมือพัฒนาคุณจะพบรหัสข้อผิดพลาด


1

เป็นข้อผิดพลาดที่รู้จักui-routerซึ่งช่วยเราได้: https://github.com/angular-ui/ui-router/issues/600


ที่ช่วยฉันอย่างมาก! คุณควรอธิบายอย่างละเอียดเกี่ยวกับเรื่องนี้และเพิ่มรหัสที่ช่วยแก้ปัญหาซึ่งอยู่ในคำตอบนี้: github.com/angular-ui/ui-router/issues/…
Lulu

0

ฉันอยากจะพูดถึงว่าฉันได้รับข้อความแสดงข้อผิดพลาดนี้เมื่อฉันพิมพ์ผิดใน templateUrl ของคำสั่งที่กำหนดเองที่ฉันมีในโครงการของฉัน เนื่องจากพิมพ์ผิดจึงไม่สามารถโหลดเทมเพลตได้

/* @ngInject */
function topNav() {
    var directive = {
        bindToController: true,
        controller: TopNavController,
        controllerAs: 'vm',
        restrict: 'EA',
        scope: {
            'navline': '=',
            'sign': '='
        },
        templateUrl: 'app/shared/layout/top-navTHIS-IS-A-TYPO.html'
    };

ดูในแท็บเครือข่ายของเครื่องมือ dev ของเว็บเบราว์เซอร์และดูว่าทรัพยากรใดมีข้อผิดพลาด 404 หรือไม่

ง่ายต่อการมองข้ามเนื่องจากข้อความแสดงข้อผิดพลาดมีความคลุมเครือและดูเหมือนจะไม่เกี่ยวข้องกับปัญหาที่แท้จริง


0

ฉันประสบปัญหานี้ในโปรเจ็กต์ของฉันเนื่องจาก. มิฉะนั้น ()ไม่มีคำจำกัดความเส้นทางของฉันและฉันกดผิดเส้นทาง


0

ฉันมีปัญหานี้เพราะฉันกำลังทำสิ่งนี้

var variableExpense = this.lodash.find(product.variableExpenseList, (ve) => {
               return ve.rawMaterial.id = rawMaterial.id;
});

แทนที่จะเป็นแบบนี้ (สังเกต = vs ===) การทดสอบหน่วยของฉันเริ่มทำลายและฉันพบความโง่เขลาของฉัน

var variableExpense = this.lodash.find(product.variableExpenseList, (ve) => {
               return ve.rawMaterial.id === rawMaterial.id;
});

0

ฉันพบปัญหานี้ซึ่งฉันต้องการคำแนะนำเครื่องมือแบบไดนามิก ... มันทำให้เชิงมุมคำนวณใหม่ทุกครั้งเป็นค่าใหม่ (แม้ว่าจะเหมือนกันก็ตาม) ฉันสร้างฟังก์ชันเพื่อแคชค่าที่คำนวณดังนี้:

$ctrl.myObj = {
    Title: 'my title',
    A: 'first part of dynamic toolip',
    B: 'second part of dynamic tooltip',
    C: 'some other value',
    getTooltip: function () {
        // cache the tooltip
        var obj = this;
        var tooltip = '<strong>A: </strong>' + obj.A + '<br><strong>B: </strong>' + obj.B;
        var $tooltip = {
            raw: tooltip,
            trusted: $sce.trustAsHtml(tooltip)
        };
        if (!obj.$tooltip) obj.$tooltip = $tooltip;
        else if (obj.$tooltip.raw !== tooltip) obj.$tooltip = $tooltip;
        return obj.$tooltip;
    }
};

จากนั้นใน html ฉันเข้าถึงได้ดังนี้:

<input type="text" ng-model="$ctrl.myObj.C" uib-tooltip-html="$ctrl.myObj.getTooltip().trusted">

0

นี่คือวิธีที่ฉันเข้าหามันและพบวิธีแก้ไข: ฉันตรวจสอบข้อความพบว่า:

Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!

ผู้ชมเริ่มทำงานในการทำซ้ำ 5 ครั้งล่าสุด: [[{"msg": "statement === statment && functionCall ()", "newVal": [{"id": 7287, "referen ...

ดังนั้นหากคุณสามารถเห็นไฟล์

ผงชูรส

นั่นคือสถิติที่สร้างข้อผิดพลาด ฉันตรวจสอบฟังก์ชั่นที่เรียกว่าในข้อความนี้ฉันส่งคืน (เท็จ) จากทั้งหมดเพื่อตรวจสอบว่าอันไหนมีปัญหา หนึ่งในนั้นเรียกใช้ฟังก์ชันที่เปลี่ยนผลตอบแทนซึ่งเป็นปัญหา


-3

อย่างบ้าคลั่งฉันแก้ไขข้อผิดพลาดนี้เพียงแค่รีสตาร์ทเบราว์เซอร์เมื่อมันถูกครอบตัดในทันที

ดังนั้นวิธีแก้ปัญหาอย่างหนึ่งคือเพียงแค่ล้างแคชของเบราว์เซอร์หรือลองรีสตาร์ทเบราว์เซอร์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.