如何用记忆法修复Angular的摘要迭代错误(附实例)

83 阅读1分钟

有时我的Angular代码失败了,有以下异常信息。**错误。10 $digest() iterations reached.终止!**我不知道那里发生了什么,也没有得到解释Angular的绑定如何工作。在这篇文章中,我将分享如何避免这个问题,以及如何在Angular应用程序中使用记忆化技术获得更好的性能。

$digest问题

所以,当你收到错误信息**Error:10 $digest() iterations reached.终止!**在你的Angular应用程序中,它实际上意味着什么?好吧,为了回答这个问题,我们必须了解Angular是如何检测变化并立即显示在用户界面上的。

这个算法非常简单--当你通过绑定在html模板中输出一个变量或函数时,就会创建一个观察者。在应用程序的生命周期中,观察者的表达式被多次调用,其结果与之前的值相匹配,如果值不同,就会触发一个相关事件,并在模板中显示新的值。要获得更多关于检测变化的信息,你可以参考这篇文章。但现在只需了解可能的问题是一个返回对象数组的函数,该函数在摘要循环中被调用。

这是很简单的演示。假设我们想遍历控制器函数中生成的用户列表:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  var data = [
    {firstName: 'John', lastName: 'Smith'},
    {firstName: 'Andrei', lastName: 'Kaleshka'}
  ];

  $scope.getUsers = function() {
    var result = [];
    angular.forEach(data, function (user) {
      result.push({fullName: user.firstName + ' ' + user.lastName});
    });
    return result;
  }
});
<div ng-repeat="user in getUsers()">
  
</div>

这个问题的发生是因为getUsers() ,尽管数组项目的属性是相同的,但每次调用都会返回不同的结果:

var res1 = [{fullName: 'John Smith'}, {fullName: 'Andrei Kaleshka'}];
var res2 = [{fullName: 'John Smith'}, {fullName: 'Andrei Kaleshka'}];
res1 === res2; // false

这就是为什么Angular的digest循环会无限地调用getUsers 。错误信息错误。达到10次$digest()迭代。中止!通知我们这个问题。

解决方案

为了解决这个问题,我们可以对函数的结果进行缓存。为此,我喜欢使用Lo-Dashmemoize函数:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  var data = [
    {firstName: 'John', lastName: 'Smith'},
    {firstName: 'Andrei', lastName: 'Kaleshka'}
  ];

  $scope.getUsers = _.memoize(function() {
    var result = [];
    angular.forEach(data, function (user) {
      result.push({fullName: user.firstName + ' ' + user.lastName});
    });
    return result;
  });
});

总结

使用这个技术,我们改善了Angular应用程序的性能,摆脱了异常**错误。达到10个digest()的迭代次数。终止了!,在digest()的迭代次数。终止了!**,在`scope` ,实现了返回对象数组的函数,这些函数可以在Angular的模板中使用。