如何选择性地从主干集合和服务器中删除模型

How do you selectively remove models from a Backbone collection and from the server?

本文关键字:服务器 删除 模型 集合 选择性      更新时间:2023-09-26

例如,如果要从todo列表中删除已完成的todo。

有选择地从主干集合和服务器中删除模型似乎是一项常见的任务。常见的方法是什么?每种方法的成本和收益是什么?

解决方案一

var toRemove = collection.filter(function(model) {
  return condition(model);
});
_.invoke(toRemove, 'destroy');

这似乎是最干净的方式。这就是Addy在他的书中用来删除已完成的todo的方法(这也是我首先列出这个解决方案的一个重要原因)。如果你重复使用过滤功能(就像他一样),它会特别干净。

然而,我认为它比解决方案二慢,因为它涉及在collectiontoRemove上的迭代,而解决方案二只涉及在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中的模型基本上会上移一个。这有两个含义:

  1. 数组的长度减少一。

  2. 假设您删除了元素二。下一个元素将是四个,而不是三个。索引增加到3,由于模型上移了1,所以3的索引为2,4的索引为3。

解决方案:

  1. 在循环的每次迭代之后计算collection.models.length。Ie.for (var i = 0; i < **collection.models.length**; i++)

  2. 销毁模型后递减i

你可以从前到后循环,但你只需要解决这些问题,这会使它变得有点复杂。


解决方案三

var toRemove = [];
collection.forEach(function(model) {
  if (condition(model)) toRemove.push(model);
});
toRemove.forEach(function(model) {
  model.destroy();
});

这与解决方案一非常相似。

差异:

  1. 我们使用forEach来构建toRemove而不是filter

  2. 我们手动迭代并调用destroy,而不是使用invoke

与解决方案一一样,您必须遍历collectiontoRemove,因此可能需要比解决方案二更长的时间。

注意:我们不能在第一个forEach循环中破坏模型。如果我们这样做,那么它的问题与解决方案2中的从前到后循环相同。为了绕过这个限制,我们必须使用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
});

这对我来说似乎有点过分,但这是一种选择。