Angular-类似流星 ORM 的一对多关系,没有无限摘要问题

Angular-meteor ORM-like one-to-many relationship without infinite-digest issues

我正在处理用户角色关系,我的代码可以正常工作,但它会在 Angular 端产生无限摘要错误,我认为这对性能有一些影响。在我的用户 class (ES2015) 中,我有:

get roles() {
  return Roles.findByIds(this._roleIds).fetch()
}

而问题是上面的getter returns每次都是一个新对象,所以在Angular眼里,他们是不平等的。我试过track by,如下:

<ul>
  <li ng-repeat="role in user.roles track by role._id">
    {{role.name}}
  </li>
</ul>

抛出以下异常:

Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations: [[{"msg":"fn: regularInterceptedExpression","newVal":20,"oldVal":19}],[{"msg":"fn: regularInterceptedExpression","newVal":21,"oldVal":20}],[{"msg":"fn: regularInterceptedExpression","newVal":22,"oldVal":21}],[{"msg":"fn: regularInterceptedExpression","newVal":23,"oldVal":22}],[{"msg":"fn: regularInterceptedExpression","newVal":24,"oldVal":23}]]

没有 track by,我看到更长的堆栈跟踪,提到 "Administrator"

Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations: [[{"msg":"fn: regularInterceptedExpression","newVal":9,"oldVal":8},{"msg":"fn: regularInterceptedExpression","newVal":"Administrator"}],[{"msg":"fn: regularInterceptedExpression","newVal":10,"oldVal":9},{"msg":"fn: regularInterceptedExpression","newVal":"Administrator"}],[{"msg":"fn: regularInterceptedExpression","newVal":11,"oldVal":10},{"msg":"fn: regularInterceptedExpression","newVal":"Administrator"}],[{"msg":"fn: regularInterceptedExpression","newVal":12,"oldVal":11},{"msg":"fn: regularInterceptedExpression","newVal":"Administrator"}],[{"msg":"fn: regularInterceptedExpression","newVal":13,"oldVal":12},{"msg":"fn: regularInterceptedExpression","newVal":"Administrator"}]]

所以现在,我的选择是避免使用 getter,并使用像这样的 updateRoles 方法:

updateRoles() {
  this.roles = Roles.findByIds(this._roleIds).fetch()
}

这消除了异常,但似乎每次 _roleIds 数组更改时我都必须手动调用 updateRoles。我只是想知道是否有比我上面提到的更好的方法。

解决这个问题的方法是使 getter 幂等。当给定相同的 _roleIds

时,它应该 return 相同的 角色数组

这是我解决这个问题的方法。我使用了类似于此 Github 评论的想法:https://github.com/angular/angular.js/issues/705#issuecomment-36737595

想法是使用 Object.defineProperty 或 (ES2015) Reflect.defineProperty 定义 getter,这样 getter 将是幂等的。

Reflect.defineProperty(this, "roles", {
  get: Model._makeIdempotent(this, "_roleIds", () => {
    return Roles.find({_id: {$in: this._roleIds}}).fetch()
  }),
})

虽然我没有在自己的代码中手动使用上述方法,并且 Reflect.define... 会在每个 "foreign key" 的循环中被调用,但这是一般的想法。