假设我的Layout
模型具有width
和height
属性。并且我想要在其中任何一个更改时更新视图,但更新过程需要计算密集且需要width
和height
的值。计算过程还会更新模型的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}}事件的方式在这种情况下效果不佳。
答案 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
的选项。