为什么 console.log 在本应只记录一次的情况下被记录多次
Why console.log is logged more than once when It should have logged only once
我正在阅读 The Complete Book on AngularJS, Ari Lerner
这本书,然后我在 ng-class 上找到了 this example。我在 generateNumber()
函数中添加了一个额外的 console.log 。我看到它只记录了一次。
之后,我将使用 x
的地方替换为 generateNumber()
函数调用。更改后我的代码看起来像这样 see this:
HTML
<!doctype html>
<html ng-app="myApp">
<head>
<link rel="stylesheet" href="//cdn.jsdelivr.net/foundation/4.3.2/css/foundation.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.js"></script>
</head>
<body>
<div ng-controller="LotteryController">
<div ng-class="{red: generateNumber() > 5}">
You won!
</div>
<button ng-click="generateNumber()">Draw Number</button>
<p>Number is: {{ x }}</p>
</div>
</body>
</html>
JS
angular.module('myApp', [])
.controller('LotteryController', function($scope) {
$scope.generateNumber = function() {
var num = Math.floor((Math.random()*10)+1);
console.log("Number: "+num);
$scope.x = num;
return num;
};
});
所以我无法理解为什么 console.log()
被记录了那么多次,甚至当我单击按钮时它应该只记录一次但它被记录了不止一次。我不明白为什么多次调用该方法。有时我也会遇到这个异常(我只粘贴了前两行)
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations:
这个 $digest 有什么用?以及为什么它达到了极限。什么是守望者?并请说明为什么要进行那么多次日志记录?
谢谢大家,
编辑
感谢大家的回复,但我想使用类似 ng-class="{red: generateNumber() > 5}"
这样做有什么问题。有人可以向我解释一下吗?我不想在那里使用 $scope.x
,所以你们现在可以忽略它。
谢谢大家,
可能是 ng-class 在每个摘要中都被验证,并且您调用了一个方法,因此它在循环中被调用。
纠正这个问题:将你的 x 添加到范围变量,然后调用生成数字来初始化你的 x
**HTML : **
<div ng-controller="LotteryController">
<div ng-class="{'red': x > 5}" ng-init="generateNumber()">
You won!
</div>
<button ng-click="generateNumber()">Draw Number</button>
<p>Number is: {{ x }}</p>
</div>
您在 ng-class 和 ng-click 中两次调用 generateNumber() 这就是它多次记录的原因。检查一下 ng-class:
的变化
angular.module('myApp', [])
.controller('LotteryController', function($scope) {
$scope.generateNumber = function() {
var num = Math.floor((Math.random()*10)+1);
console.log("Number: "+num);
$scope.x = num;
return num;
};
});
<!doctype html>
<html ng-app="myApp">
<head>
<link rel="stylesheet" href="//cdn.jsdelivr.net/foundation/4.3.2/css/foundation.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.js"></script>
</head>
<body>
<div ng-controller="LotteryController">
<div ng-class="{red: x > 5}">
You won!
</div>
<button ng-click="generateNumber()">Draw Number</button>
<p>Number is: {{ x }}</p>
</div>
</body>
</html>
console.log 在每个 $scope.$digest 被调用,因为你使用方法 $scope.generateNumber 作为 ng-class 的条件,在内部 generateNumber() 修改 $scope.x 变量导致新的 $digest 循环到 运行.
在每个 $digest 循环中调用生成数字以确定是否应用 class。
使用 $scope.x 作为 ng-class
的条件
angular.module('myApp', [])
.controller('LotteryController', function($scope) {
$scope.generateNumber = function() {
var num = Math.floor((Math.random()*10)+1);
console.log("Number: "+num);
$scope.x = num;
return num;
};
});
<!doctype html>
<html ng-app="myApp">
<head>
<link rel="stylesheet" href="//cdn.jsdelivr.net/foundation/4.3.2/css/foundation.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.js"></script>
</head>
<body>
<div ng-controller="LotteryController">
<div ng-class="{red: x > 5}">
You won!
</div>
<button ng-click="generateNumber()">Draw Number</button>
<p>Number is: {{ x }}</p>
</div>
</body>
</html>
根据 doc:
Processes all of the watchers of the current scope and its children.
Because a watcher's listener can change the model, the $digest() keeps
calling the watchers until no more listeners are firing. This means
that it is possible to get into an infinite loop. This function will
throw 'Maximum iteration limit exceeded.' if the number of iterations
exceeds 10.
换句话说,$digest 是您的视图与 $scope 同步的过程。在 digest 开始后,它循环直到 $scope
的状态与其在刚刚过去的循环中的状态相比没有改变。
作用域状态的变化是通过评估 watch 表达式(明确定义或隐含在您的观点中)来确定的。如果每个表达式在连续循环中的计算结果相同,则摘要将结束。
为了具体解决您的观察,generateNumber()
总是 returns 一个新号码!所以 $digest 进程总是看到范围的状态在每个循环结束时发生变化。经过 10 个循环后,系统猜测它处于无限循环中,因此它抛出了您观察到的异常(并且如文档中指定的那样)。
您可以通过以下方法解决问题:
$scope.generateNumber = function () {
$scope.x = Math.floor((Math.random() * 10) + 1);
console.log("Number: " + $scope.x);
};
接下来应对您的标记进行以下更改:
<div ng-class="{red: x > 5}">
You won!
</div>
正如我读到的,您在其中一条评论中说“我不想直接使用 x,”;那么创建一个 returns class 映射对象的方法就足够了,或者直接将 class 映射对象添加到范围,或者添加一个 returns 的方法生成的数字到范围。
1。添加一个方法,将生成的数字 returns 添加到范围
JS:
var number;
$scope.getNumber = function () {
return number;
};
$scope.generateNumber = function () {
$scope.x = Math.floor((Math.random() * 10) + 1);
number = $scope.x;
console.log("Number: " + $scope.x);
};
HTML
<div ng-class="getNumber() > 5">
You won!
</div>
2。使用 returns class 地图对象
的方法
JS:
var classMap = {};
$scope.getClassMap = function () {
classMap.red = $scope.x > 5;
return classMap;
};
HTML
<div ng-class="getClassMap()">
You won!
</div>
3。直接将 class 地图对象添加到范围
JS:
$scope.classMap = {};
$scope.generateNumber = function () {
$scope.x = Math.floor((Math.random() * 10) + 1);
$scope.classMap.red = $scope.x > 5;
console.log("Number: " + $scope.x);
};
HTML
<div ng-class="classMap">
You won!
</div>
我正在阅读 The Complete Book on AngularJS, Ari Lerner
这本书,然后我在 ng-class 上找到了 this example。我在 generateNumber()
函数中添加了一个额外的 console.log 。我看到它只记录了一次。
之后,我将使用 x
的地方替换为 generateNumber()
函数调用。更改后我的代码看起来像这样 see this:
HTML
<!doctype html>
<html ng-app="myApp">
<head>
<link rel="stylesheet" href="//cdn.jsdelivr.net/foundation/4.3.2/css/foundation.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.js"></script>
</head>
<body>
<div ng-controller="LotteryController">
<div ng-class="{red: generateNumber() > 5}">
You won!
</div>
<button ng-click="generateNumber()">Draw Number</button>
<p>Number is: {{ x }}</p>
</div>
</body>
</html>
JS
angular.module('myApp', [])
.controller('LotteryController', function($scope) {
$scope.generateNumber = function() {
var num = Math.floor((Math.random()*10)+1);
console.log("Number: "+num);
$scope.x = num;
return num;
};
});
所以我无法理解为什么 console.log()
被记录了那么多次,甚至当我单击按钮时它应该只记录一次但它被记录了不止一次。我不明白为什么多次调用该方法。有时我也会遇到这个异常(我只粘贴了前两行)
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations:
这个 $digest 有什么用?以及为什么它达到了极限。什么是守望者?并请说明为什么要进行那么多次日志记录? 谢谢大家,
编辑
感谢大家的回复,但我想使用类似 ng-class="{red: generateNumber() > 5}"
这样做有什么问题。有人可以向我解释一下吗?我不想在那里使用 $scope.x
,所以你们现在可以忽略它。
谢谢大家,
可能是 ng-class 在每个摘要中都被验证,并且您调用了一个方法,因此它在循环中被调用。
纠正这个问题:将你的 x 添加到范围变量,然后调用生成数字来初始化你的 x
**HTML : **
<div ng-controller="LotteryController">
<div ng-class="{'red': x > 5}" ng-init="generateNumber()">
You won!
</div>
<button ng-click="generateNumber()">Draw Number</button>
<p>Number is: {{ x }}</p>
</div>
您在 ng-class 和 ng-click 中两次调用 generateNumber() 这就是它多次记录的原因。检查一下 ng-class:
的变化angular.module('myApp', [])
.controller('LotteryController', function($scope) {
$scope.generateNumber = function() {
var num = Math.floor((Math.random()*10)+1);
console.log("Number: "+num);
$scope.x = num;
return num;
};
});
<!doctype html>
<html ng-app="myApp">
<head>
<link rel="stylesheet" href="//cdn.jsdelivr.net/foundation/4.3.2/css/foundation.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.js"></script>
</head>
<body>
<div ng-controller="LotteryController">
<div ng-class="{red: x > 5}">
You won!
</div>
<button ng-click="generateNumber()">Draw Number</button>
<p>Number is: {{ x }}</p>
</div>
</body>
</html>
console.log 在每个 $scope.$digest 被调用,因为你使用方法 $scope.generateNumber 作为 ng-class 的条件,在内部 generateNumber() 修改 $scope.x 变量导致新的 $digest 循环到 运行.
在每个 $digest 循环中调用生成数字以确定是否应用 class。
使用 $scope.x 作为 ng-class
的条件angular.module('myApp', [])
.controller('LotteryController', function($scope) {
$scope.generateNumber = function() {
var num = Math.floor((Math.random()*10)+1);
console.log("Number: "+num);
$scope.x = num;
return num;
};
});
<!doctype html>
<html ng-app="myApp">
<head>
<link rel="stylesheet" href="//cdn.jsdelivr.net/foundation/4.3.2/css/foundation.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.js"></script>
</head>
<body>
<div ng-controller="LotteryController">
<div ng-class="{red: x > 5}">
You won!
</div>
<button ng-click="generateNumber()">Draw Number</button>
<p>Number is: {{ x }}</p>
</div>
</body>
</html>
根据 doc:
Processes all of the watchers of the current scope and its children. Because a watcher's listener can change the model, the $digest() keeps calling the watchers until no more listeners are firing. This means that it is possible to get into an infinite loop. This function will throw 'Maximum iteration limit exceeded.' if the number of iterations exceeds 10.
换句话说,$digest 是您的视图与 $scope 同步的过程。在 digest 开始后,它循环直到 $scope
的状态与其在刚刚过去的循环中的状态相比没有改变。
作用域状态的变化是通过评估 watch 表达式(明确定义或隐含在您的观点中)来确定的。如果每个表达式在连续循环中的计算结果相同,则摘要将结束。
为了具体解决您的观察,generateNumber()
总是 returns 一个新号码!所以 $digest 进程总是看到范围的状态在每个循环结束时发生变化。经过 10 个循环后,系统猜测它处于无限循环中,因此它抛出了您观察到的异常(并且如文档中指定的那样)。
您可以通过以下方法解决问题:
$scope.generateNumber = function () {
$scope.x = Math.floor((Math.random() * 10) + 1);
console.log("Number: " + $scope.x);
};
接下来应对您的标记进行以下更改:
<div ng-class="{red: x > 5}">
You won!
</div>
正如我读到的,您在其中一条评论中说“我不想直接使用 x,”;那么创建一个 returns class 映射对象的方法就足够了,或者直接将 class 映射对象添加到范围,或者添加一个 returns 的方法生成的数字到范围。
1。添加一个方法,将生成的数字 returns 添加到范围
JS:
var number;
$scope.getNumber = function () {
return number;
};
$scope.generateNumber = function () {
$scope.x = Math.floor((Math.random() * 10) + 1);
number = $scope.x;
console.log("Number: " + $scope.x);
};
HTML
<div ng-class="getNumber() > 5">
You won!
</div>
2。使用 returns class 地图对象
的方法JS:
var classMap = {};
$scope.getClassMap = function () {
classMap.red = $scope.x > 5;
return classMap;
};
HTML
<div ng-class="getClassMap()">
You won!
</div>
3。直接将 class 地图对象添加到范围
JS:
$scope.classMap = {};
$scope.generateNumber = function () {
$scope.x = Math.floor((Math.random() * 10) + 1);
$scope.classMap.red = $scope.x > 5;
console.log("Number: " + $scope.x);
};
HTML
<div ng-class="classMap">
You won!
</div>