$ digest()の反復が10回に達しました。中止します!
「最後の5回のイテレーションで発生したウォッチャー:」などの意味で多くのサポートテキストがありますが、このテキストの多くはさまざまな関数からのJavaScriptコードです。この問題を診断するための経験則はありますか?常に軽減できる問題ですか、それともこの問題を単なる警告として扱う必要があるほど複雑なアプリケーションがありますか?
回答:
Venが言ったように、$digest
サイクルごとに異なる(同一ではない)オブジェクトを返すか、データを何度も変更しています。
アプリのどの部分がこの動作を引き起こしているのかを突き止めるための最速のソリューションは次のとおりです。
$scope
か、各$digest
サイクルで同一でないオブジェクトを返します。$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
map()
、groupBy()
あなたのES$watch
がダーティチェックを実行することobjectEquality
$watch('myFunctionDoingGropby',callback,true)
を確認した場合は、docs.angularjs.org
$scope
、_.map
-edリストが一度割り当てられる変数に置き換えることができましたが、一般的に、オブジェクトの等価性によるダーティチェックにどのように影響しますか。$watch
作動しているのは手動で作成したものではありませんが、ngRepeat
?
通常、毎回異なるオブジェクトを返すときに発生します。
たとえば、これを次のように使用するとしますng-repeat
。
$scope.getObj = function () {
return [{a: 1}, {b: 2}];
};
Angularは「安定性」を保持しようとし、同じ結果が2回返されるまで(と比較して===
)関数を実行するため、このエラーメッセージが表示されます。この場合、関数は常にaを返すため、trueは返されません。新しいオブジェクト。
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...)
(複雑なアプリケーションであっても、これに遭遇することはありません)。
更新:Angularのウェブサイトにさらに詳しい説明が追加されました。
このソリューションをここに投入したかったのですが、うまくいけば他の人の役に立つでしょう。呼び出されるたびに新しいオブジェクトを作成する生成されたプロパティを繰り返し処理していたため、この反復問題が発生していました。
生成されたオブジェクトが最初に要求されたときにキャッシュし、存在する場合は常にキャッシュを返すことで修正しました。必要に応じてキャッシュされた結果を破棄する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回の反復は、それを確実に結論付けるのに十分な数ではありません。したがって、野生のガチョウを追いかける前に、まずその可能性を除外することをお勧めします。
そのための最も簡単な方法は、最大ダイジェストループカウントをはるかに大きな数に増やすことです。これは、module.config
メソッドを使用してメソッドで実行できます$rootScopeProvider.digestTtl(limit)
。infdig
エラーが発生しなくなった場合は、十分に複雑な更新ロジックがあるだけです。
再帰的な監視に依存するデータまたはビューを構築する場合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を削減するなど、すでに述べた方法はもちろん役に立ちます。
これはの既知のバグですui-router
。これは私たちを助けてくれました:https : //github.com/angular-ui/ui-router/issues/600
また、プロジェクトにあるカスタムディレクティブの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'
};
Webブラウザーの開発ツールのネットワークタブで、404エラーが発生しているリソースがないかどうかを確認します。
エラーメッセージは非常に不可解であり、実際の問題とは一見無関係であるため、見落としがちです。
私がこれをしていたので、私はこの問題を抱えていました
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;
});
動的なツールチップが必要なこの問題に出くわしました…(同じであっても)angularが毎回新しい値として再計算しました。次のように計算値をキャッシュする関数を作成しました。
$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">
これが私がそれにアプローチして解決策を見つけた方法です:私はテキストをチェックしました、それは示しました:
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
ウォッチャーは過去5回の反復で発生しました:[[{"msg": "statement === statment && functionCall()"、 "newVal":[{"id":7287、 "referen ...
だからあなたが見ることができるなら
メッセージ
それはエラーを生成するステートメントです。このメッセージで呼び出された関数を確認したところ、問題のあるものを特定するためだけに、それらすべてから(false)が返されました。それらの1つは、戻り値を変更し続ける関数を呼び出していました。これが問題です。