角度过滤器工作但导致“10 $digest 迭代达到" [英] Angular filter works but causes "10 $digest iterations reached"

查看:23
本文介绍了角度过滤器工作但导致“10 $digest 迭代达到"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从后端服务器接收数据,结构如下:

I receive data from my back end server structured like this:

{
  name : "Mc Feast",
  owner :  "Mc Donalds"
}, 
{
  name : "Royale with cheese",
  owner :  "Mc Donalds"
}, 
{
  name : "Whopper",
  owner :  "Burger King"
}

对于我的观点,我想反转"列表.IE.我想列出每个所有者,并为该所有者列出所有汉堡包.我可以通过在过滤器中使用 underscorejs 函数 groupBy 来实现这一点,然后我将其与 ng-repeat 指令一起使用:

For my view I would like to "invert" the list. I.e. I want to list each owner, and for that owner list all hamburgers. I can achieve this by using the underscorejs function groupBy in a filter which I then use in with the ng-repeat directive:

JS:

app.filter("ownerGrouping", function() {
  return function(collection) {
    return _.groupBy(collection, function(item) {
      return item.owner;
    });
  }
 });

HTML:

<li ng-repeat="(owner, hamburgerList) in hamburgers | ownerGrouping">
  {{owner}}:  
  <ul>
    <li ng-repeat="burger in hamburgerList | orderBy : 'name'">{{burger.name}}</li>
  </ul>
</li>

这按预期工作,但是当列表呈现错误消息达到 10 $digest 迭代"时,我得到了一个巨大的错误堆栈跟踪.我很难看到我的代码如何创建此消息所暗示的无限循环.有人知道为什么吗?

This works as expected but I get an enormous error stack trace when the list is rendered with the error message "10 $digest iterations reached". I have a hard time seeing how my code creates an infinite loop which is implied by this message. Does any one know why?

这是带有代码的 plunk 的链接:http://plnkr.co/edit/8kbVuWhOMlMojp0E5Qbs?p=预览

Here is a link to a plunk with the code: http://plnkr.co/edit/8kbVuWhOMlMojp0E5Qbs?p=preview

推荐答案

发生这种情况是因为 _.groupBy 每次运行时都会返回一个 new 对象的集合.Angular 的 ngRepeat 没有意识到这些对象是相等的,因为 ngRepeat 通过 identity 跟踪它们.新对象导致新身份.这让 Angular 认为自上次检查以来发生了一些变化,这意味着 Angular 应该运行另一次检查(又名摘要).下一个摘要最终会获得另一组新对象,因此触发另一个摘要.重复直到 Angular 放弃.

This happens because _.groupBy returns a collection of new objects every time it runs. Angular's ngRepeat doesn't realize that those objects are equal because ngRepeat tracks them by identity. New object leads to new identity. This makes Angular think that something has changed since the last check, which means that Angular should run another check (aka digest). The next digest ends up getting yet another new set of objects, and so another digest is triggered. The repeats until Angular gives up.

消除错误的一种简单方法是确保您的过滤器每次都返回相同的对象集合(当然除非它已更改).您可以使用 _.memoize 使用下划线轻松完成此操作.只需将过滤器功能包装在 memoize 中:

One easy way to get rid of the error is to make sure your filter returns the same collection of objects every time (unless of course it has changed). You can do this very easily with underscore by using _.memoize. Just wrap the filter function in memoize:

app.filter("ownerGrouping", function() {
  return _.memoize(function(collection, field) {
    return _.groupBy(collection, function(item) {
      return item.owner;
    });
  }, function resolver(collection, field) {
    return collection.length + field;
  })
});

如果您计划为过滤器使用不同的字段值,则需要解析器函数.在上面的例子中,使用了数组的长度.最好将集合减少为唯一的 md5 哈希字符串.

A resolver function is required if you plan to use different field values for your filters. In the example above, the length of the array is used. A better be to reduce the collection to a unique md5 hash string.

在此处查看 plunker 叉.Memoize 将记住特定输入的结果,如果输入与以前相同,则返回相同的对象.如果值频繁变化,那么您应该检查 _.memoize 是否丢弃旧结果以避免内存泄漏.

See plunker fork here. Memoize will remember the result of a specific input and return the same object if the input is the same as before. If the values change frequently though then you should check if _.memoize discards old results to avoid a memory leak over time.

进一步调查我发现 ngRepeat 支持扩展语法 ... track by EXPRESSION,这可能会以某种方式帮助您告诉 Angular 查看餐厅的 owner 而不是对象的身份.这将是上述记忆化技巧的替代方法,尽管我无法在 plunker 中对其进行测试(可能是 track by 实施之前的旧版 Angular?).

Investigating a bit further I see that ngRepeat supports an extended syntax ... track by EXPRESSION, which might be helpful somehow by allowing you to tell Angular to look at the owner of the restaurants instead of the identity of the objects. This would be an alternative to the memoization trick above, though I couldn't manage to test it in the plunker (possibly old version of Angular from before track by was implemented?).

这篇关于角度过滤器工作但导致“10 $digest 迭代达到"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆