例如,如果要从待办事项列表中删除已完成的待办事项。
从Backbone集合和服务器中有选择地删除模型似乎是一项常见任务。有哪些常见的方法,以及与每种方式相关的成本和收益是什么?
答案 0 :(得分:1)
解决方案一
var toRemove = collection.filter(function(model) {
return condition(model);
});
_.invoke(toRemove, 'destroy');
这似乎是最干净的方式。这是Addy used在他的书中删除已完成的待办事项(这是我首先列出此解决方案的一个重要原因)。如果你重复使用过滤功能(就像他一样),它会特别干净。
但是,我认为它比解决方案二慢,因为它涉及collection
和toRemove
的迭代,而解决方案二只涉及collection
的迭代。尽管如此,它们都有线性运行时间,因此它并不是一件大事。
解决方案二
for (var i = collection.models.length-1; i >= 0; i--) { // looping from back to front
var model = collection.models[i];
if (condition(model)) model.destroy();
}
我觉得这个比较干净。如上所述,这样做的好处就是只需要遍历集合,而不是集合+集合的过滤版本。
从后到前循环非常重要。考虑从前到后循环时会发生什么:
for (var i = 0; i < collection.models.length; i++) { // looping from front to back
var model = this.models[i];
if (condition(model)) {
model.destroy();
i--;
}
}
当您销毁模型时,collection.models
中的模型基本上会向上移动一个。这有两个含义:
数组的长度减少一个。
假设你删除了第二个元素。下一个元素将是四个,而不是三个。索引增加到3,并且由于模型向上移动一个,三个索引为2,四个索引为3.
解决方案:
在循环的每次迭代后计算collection.models.length
。 IE浏览器。 for (var i = 0; i < **collection.models.length**; i++)
销毁模型后减少i
。
你可以从前到后循环,但你只需要处理这些事情,这会使它更复杂。
解决方案三
var toRemove = [];
collection.forEach(function(model) {
if (condition(model)) toRemove.push(model);
});
toRemove.forEach(function(model) {
model.destroy();
});
这与Solution One非常相似。
的差异:
我们使用forEach
来构建toRemove
而不是filter
。
我们手动迭代并调用destroy
而非使用invoke
。
与解决方案一一样,您必须遍历collection
和toRemove
,因此它可能需要比解决方案二更长的时间。
注意:我们无法在第一个forEach
循环中销毁模型。如果我们这样做,那么它与解决方案二中的前后循环具有相同的问题。要解决此限制,我们必须使用toRemove
数组。
解决方案四
这会使用reset()
+ reset
事件。
var toKeep = collection.filter(function(model) {
return condition(model);
});
collection.reset(toKeep);
和
collection.on('reset', function(after, before) {
// let after.length = k
// let before.length = n
after.sort(); // k*logk
for (var i = before.length-1; i >= 0; i--) { // n
var model = before[i];
if (!binarySearch(model, after)) model.remove(); // logk
}
// total runtime: n*logk + k*logk
});
这对我来说似乎有些过分,但是可以选择。