为什么console.log会被记录多次,因为它应该只记录一次

时间:2015-08-24 13:45:48

标签: javascript angularjs angular-digest

我正在阅读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:

这个$摘要是什么?以及它达到极限的原因。观察者是什么?并请说为什么多次进行日志记录? 谢谢你们,

修改

感谢回复人员,但我想使用像ng-class="{red: generateNumber() > 5}"之类的东西。这样做有什么不对。谁能解释我这个。我不想在那里使用$scope.x,所以你们现在可以忽略它。

谢谢你们,

4 个答案:

答案 0 :(得分:1)

可能在每个摘要中验证了ng-class,并且您调用了一个方法,以便在循环中调用它。

要纠正错误:将x添加到范围变量中,然后调用generate number来初始化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>

答案 1 :(得分:1)

在每个$ scope。$ digest上调用console.log,因为你使用$ scope.generateNumber方法作为ng-class的条件,内部generateNumber()修改$ scope.x变量,导致新的$ digest循环运行。

在每个$ digest循环中,调用生成数来确定是否应用该类。

使用$ 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>

答案 2 :(得分:1)

根据doc

  

处理当前范围及其子项的所有观察者。   因为观察者的监听器可以改变模型,所以$ digest()保持不变   打电话给观察者直到不再有听众开枪。这意味着   有可能进入无限循环。这个功能会   抛出'超出最大迭代次数'。如果迭代次数   超过10。

换句话说, $ digest 是您的视图与$ scope同步的过程。 摘要 启动后,它会一直循环,直到$scope的状态与前一个周期的状态相比没有变化。

范围状态的变化是通过评估 监视 表达式(在视图中明确定义或隐含)来确定的。如果每个表达式在连续的周期内评估相同的结果,那么摘要将结束。

为了明确解决您的观察问题,generateNumber()始终会返回一个新号码!因此, $ 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,直接”;那么只需创建一个返回类映射对象的方法,或者直接将类映射对象添加到作用域,或者添加一个将生成的数字返回给作用域的方法就足够了。

1。添加一个方法,将生成的数字返回到范围

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。使用返回类映射对象的方法

JS:

var classMap = {};
$scope.getClassMap = function () {
    classMap.red = $scope.x > 5;
    return classMap;
};

HTML

  <div ng-class="getClassMap()">
    You won!
  </div>

3。直接将类映射对象添加到范围

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>

答案 3 :(得分:0)

你在ng-class和ng-click中调用generateNumber()twise,这就是它多次记录的原因。检查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>