内容简介:AngularJS 无限Digest循环导致的错误(infdig)
最近在开发Angular项目过程中遇到一个问题, 日期相关, 核心错误点在于我把一个日期对象挂到$scope 上, view 里面两个地方分别用到了当天和后一天, 大概的示例代码如下:
// test.ctrl.js var app = angular.module('ericTestApp', ['ngRoute']).config(['$routeProvider', function ($routeProvider) { $routeProvider.when('/bad', { controller: 'BadCtrl', template: '<div>today: {{today | date :"yyyy-MM-dd HH:mm:ss"}}</div><div>today: {{tomorrow() | date :"yyyy-MM-dd HH:mm:ss"}}</div>' }).otherwise({ redirectTo: '/bad' }); }]); app.controller('BadCtrl', ['$scope', function ($scope) { $scope.today = new Date(); $scope.tomorrow = function () { console.log('tomorrow called ' + $scope.today); var tmr = $scope.today; tmr = tmr.setDate(tmr.getDate() + 1); return tmr; }; }]);
上面的代码运行起来会抛出 Error: $rootScope:infdig Infinite $digest Loop
的错误信息, 这问题涉及到两个点, 一是对象引用; 二是Angular 的$digest 循环和它的脏值检测.
我们重点来了解一下Angular 的$digest 循环, Angular 最突破性的特性就是他的双向绑定, 开始使用的时候确实会觉得非常爽, 但是他是如何来保证数据的同步更新的呢? 实际上使用了一个比较暴力的方式, 也就是每个view 中的expression去连续执行N遍, 如果所有的表达式值两次都一样, 那说明已经稳定(最后两次计算的值相等)了, 此时结束循环. 如果中间检测到某表达式的值两次计算有差异, 那就继续再都循环一次, 直到所有view 中表达式的值稳定. 那么问题来了, 如果一直不会稳定呢? 目前Angular 的处理是循环超过10次就报错.
看到这里, 应该很多人已经看出上面代码的问题了, 在tomorrow 函数中, 拿到了today 的引用加了一天以后重新赋给它, 这样导致每次循环在计算tomorow() 的值的时候, today 被改变了, 下次循环, 因为today被上次改了, tomorrow() 的返回值也随之改变, 所以会触发下次循环, 如此循环下去达到了Angular 容忍的 digest 循环最大次数(Angular 中称为digestTTL)而抛出错误.
上面说的问题我们可以用几个Demo 验证一下增强理解, Demo 代码见 http://jsbin.com/coxeru/edit?html,js,console,output :
抛出infdig error
// 绑定到view 的 scope 方法里面修改另一个scope 的值, 会造成无限循环. app.controller('BadCtrl', function ($scope) { $scope.today = new Date(); $scope.tomorrow = function () { console.log('tomorrow called ' + $scope.today); var tmr = $scope.today; tmr = tmr.setDate(tmr.getDate() + 1); return tmr; }; });
正确的做法, 绑定到$scope 的函数不去改变另外一个$ scope 的值
// 正常运行 app.controller('GoodCtrl', function ($scope) { $scope.today = new Date(); $scope.tomorrow = function () { console.log('tomorrow called' + $scope.today); var tmrInMs = $scope.today.getTime(); tmr = new Date(tmrInMs + (24 * 60 * 60 * 1000)); return tmr; }; }); ``` 当然, Angular 的官网文档中也说明了几种常见导致无限digest 循环的错误, 在开发过程中也需要注意. {% asset_img angular-doc-infdig.png %} 最后我们用一个Demo 演示了设置digstTTL的作用, 也方便进一步理解digest 循环 ``` js var digestTTL = 3; // 手动设置digestTTL var app = angular.module('ericTestApp', ['ngRoute']).config(['$routeProvider', '$rootScopeProvider', function ($routeProvider, $rootScopeProvider) { $routeProvider.when('/deepTest', { controller: 'DeepTestCtrl', template: '<div>today: {{today | date :"yyyy-MM-dd HH:mm:ss"}}</div><div>today: {{tomorrow() | date :"yyyy-MM-dd HH:mm:ss"}}</div>' }).otherwise({ redirectTo: '/deepTest' }); // 手动设置digestTTL $rootScopeProvider.digestTtl(digestTTL); }]); // 用于测试Angular Digest的次数 var n = 1; app.controller('DeepTestCtrl', function ($scope) { $scope.today = new Date(); $scope.tomorrow = function () { var tmrInMs = $scope.today.getTime(); console.log("digest " + n++); tmr = new Date(tmrInMs + (24 * 60 * 60 * 1000) * n); return tmr; }; });
我们看到返回结果打印4条日志, 且第4条的时候因为返回的值还未稳定, 直接抛出了错误. 这也验证了我们上面的说法. 因此在开发过程中改变$scope 上挂的东西的时候需要谨慎, 因为你不知道你写的这个方法什么时候被别人放到view 上去, 或者watch 起来. 当然理解了此错误的产生原因以后即使遇到也应该不难解决了.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 一个让人惊讶的排序导致的死循环问题
- 008.Python循环for循环
- 006.Python循环语句while循环
- 007.Python循环语句while循环嵌套
- 观点 | 激励循环——加密算法如何实际修复现有激励循环
- 数组常见的遍历循环方法、数组的循环遍历的效率对比
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
PHP实战
Dagfinn Reiersol、Marcus Baker、Chris Shiflett / 张颖 等、段大为 审校 / 人民邮电出版社 / 2010-01 / 69.00元
“对于那些想要在PHP方面更进一步的开发者而言,此书必不可少。” ——Gabriel Malkas, Developpez.com “简而言之,这是我所读过的关于面向对象编程和PHP最好的图书。……强烈推荐此书,绝不要错过!” ——Amazon评论 “此书是理论与实践的完美融合,到目前为止,其他任何图书都无法与它相媲美。如果5颗星是满分,它完全值得10颗星!” ——A......一起来看看 《PHP实战》 这本书的介绍吧!
HTML 压缩/解压工具
在线压缩/解压 HTML 代码
CSS 压缩/解压工具
在线压缩/解压 CSS 代码