【问题标题】:Nested backbone model results in infinite recursion when saving嵌套主干模型在保存时导致无限递归
【发布时间】:2013-11-19 23:56:20
【问题描述】:

这个问题似乎是在我更新到 Backbone 1.1 时出现的。我有一个嵌套的 Backbone 模型:

var ProblemSet = Backbone.Model.extend({
    defaults: {
        name: "",
        open_date: "",
        due_date: ""},
    parse: function (response) {
        response.name = response.set_id;
        response.problems = new ProblemList(response.problems);
        return response; 
    }
});

var ProblemList = Backbone.Collection.extend({
     model: Problem
});

我最初加载了一个 ProblemSetList,它是我页面中的 ProblemSet 模型的集合。对任何 ProblemSet 的 open_date 或 due_date 字段的任何更改,首先转到服务器并更新该属性,然后返回。这会在 ProblemSet 上触发另一个更改事件。

似乎所有来自服务器的后续返回都会触发另一个更改事件,并且更改的属性是“问题”属性。这会导致无限递归调用。

问题似乎来自 Backbone.Model 的 set 方法部分(此处列出的代码从第 339 行开始)

// For each `set` attribute, update or delete the current value.
for (attr in attrs) {
    val = attrs[attr];
    if (!_.isEqual(current[attr], val)) changes.push(attr);
    if (!_.isEqual(prev[attr], val)) {
      this.changed[attr] = val;
    } else {
      delete this.changed[attr];
    }
    unset ? delete current[attr] : current[attr] = val;
  }

  // Trigger all relevant attribute changes.
  if (!silent) {
    if (changes.length) this._pending = true;
    for (var i = 0, l = changes.length; i < l; i++) {
      this.trigger('change:' + changes[i], this, current[changes[i]], options);
    }
  }

对问题属性的比较从 _.isEqual() 中返回 false,因此会触发一个更改事件。

我的问题是:这是做嵌套主干模型的正确方法吗?我在 Backbone 1.1 中有类似的工作。关于如何避免此问题的其他想法?

【问题讨论】:

  • 我了解到您已将save 绑定到模型的change 事件?
  • 是的。就像:problemSets.on("change",function(_set){ _set.save();});
  • 我最近认为骨干 1.1 不是问题,而是强调它也更新到 1.5.2,并且对带有对象的 _.isEqual 函数进行了一些更改。
  • 更多探索使我得出以下结论:我上面引用的 Backbone.js 代码正在返回一个更改变量,这意味着当前对象与刚刚从服务器发送的对象之间存在差异。似乎原因是新对象的ID与旧对象不同;我在想,因为他们通过了 parse 命令(上面列出)并创建了一个新的 ProblemList。一对新的问题可能是:对于像这样的嵌套模型,我应该不创建一个新的 ProblemList 集合(并保留旧的 id)还是有其他方法?

标签: backbone.js


【解决方案1】:

每次您的model.fetch 完成时,您都会重新实例化您的problems 属性,对象是不同的,因此会触发一个新的循环。

我通常如何处理嵌套模型:

  • 在 Backbone 处理的属性之外使用模型属性,
  • initialize函数中实例化它,
  • setresetparse 函数中的此对象并返回省略设置数据的响应

类似这样的:

var ProblemSet = Backbone.Model.extend({
    defaults: {
        name: "",
        open_date: "",
        due_date: ""
    },
    initialize: function (opts) {
        var pbs = (opts && opts.problems) ? opts.problems : [];
        this.problems = new ProblemList(pbs);
    },
    parse: function (response) {
        response.name = response.set_id;
        if (response.problems)
            this.problems.set(response.problems);
        return _.omit(response, 'problems');
    }
});

【讨论】:

  • 谢谢。如果你有机会,我的另一个一般问题是如何存储嵌套模型。看来您将它作为对象的字段(例如 ProblemSet)而不是在属性列表中。您在上面列出的方式是更可取的方式吗?
  • @PeterStaab 非常主观,但我更喜欢这种方式,因为正如您的问题所证明的那样,我不希望在我重置/获取/煎炸属性(或在任何地方引入条件)时更改底层对象) 我觉得它'更容易和更清洁处理。当然,en.wikipedia.org/wiki/There%27s_more_than_one_way_to_do_it
【解决方案2】:

parse 在获取和保存时被调用(根据主干文档),这可能会导致您的无限循环。我认为 parse 函数不是创建新 ProblemsList 子集合的正确位置,而是在模型的初始化函数中进行。

【讨论】:

  • parse 中创建嵌套的主干模型/集合是一种既定做法
  • 哦,谢谢你的提示,以前没见过这个;)
猜你喜欢
  • 1970-01-01
  • 2019-02-24
  • 1970-01-01
  • 2012-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-10
  • 2014-12-21
相关资源
最近更新 更多