Backbone.Model如何只监听多个属性的更改一次

时间:2014-11-17 18:06:34

标签: backbone.js backbone-model

假设我的Layout模型具有widthheight属性。并且我想要在其中任何一个更改时更新视图,但更新过程需要计算密集且需要widthheight的值。计算过程还会更新模型的ratio属性。

如果我这样做

this.listenTo(this.model, 'change:width change:height', this.doLayout);

在最糟糕的情况下,我最终会进行两次doLayout次呼叫,两者都会做同样的事情,浪费资源。

如果我这样做

this.listenTo(this.model, 'change', function(model) {
    if(model.hasChanged('width') || model.hasChanged('height')) {
        this.doLayout();
    }
});

乍一看,我似乎解决了两次进行doLayout计算的问题。 Backbone.Model的工作方式是,由于doLayout设置了ratio,我最终会遇到第二个change事件。第一个事件的changedAttributes{width: ..., height: ...},第二个事件的{width: ..., height: ..., ratio: ...}doLayout。所以是的,set再次执行两次......

除了重写change方法之外的任何解决方案?

编辑:请注意,我需要一个通用的解决方案。不允许对宽度/高度/比率特殊情况进行硬编码。实际上,我有更多基于其他属性更新的计算属性,Backbone处理{{1}}事件的方式在这种情况下效果不佳。

2 个答案:

答案 0 :(得分:4)

无论如何,对我来说最简单的事情就是改变你对事件的看法。例如,在这种情况下,并不是你只想做一次,而是你想在两个完成之后做一些事情。

这里最简单的方法是去除事件:

this.listenTo(this.model, 'change:width change:height', _.debounce(this.doLayout, 1));

这样它只会运行一次,即使它被同步调用了很多次。

注意:_.debounce(..., 1)的确切时序行为取决于浏览器对非常小的超时的处理。如果类似于类似同步的行为很重要,则可以使用setImmediate编写的自定义debouncer替换_.debounce的用法。

答案 1 :(得分:0)

我提出了一个很好的解决方案,不应该有任何副作用。

Backbone.Mode.extend({
    set: function() {
        this.changed = {};
        Backbone.Model.prototype.set.apply(this, arguments);
    }
});

如果您查看Backbone源并检查this.changed的使用位置,应该清楚这是做什么的。 change:[attr]类型的事件根本不受影响。但在change事件中,changedAttributes()hasChanged()只返回最后一次set调用所更改的属性。

我考虑向Backbone提交拉取请求,这可以将其配置为set的选项。