js 不定时更新数组问题

daokeaaaaa
  • 23

问题:往一个数组中push对象,对象的唯一标识为name,当push到某个对象时,发现数组中存在 name相等的对象,此时如何更新数组中name相同的对象为当前要push的对象,如果数组中的对象已经存在>6秒则删除此对象。

代码:

const objArray = [{name: 1, other: 2}, {name: 2, other: 2}];
const addObj = {name: 2, other: 4}
const index = objArray.findIndex(i => i.name === addObj.name);
if(index > -1) {
    objArray[index] = addObj;
} else {
    objArray.push(addObj);
}

不定时向objArray push对象,name相等则更新且当前对象存在数组的时间重新计算,不相等就push,那么如果数组中的对象存在6秒且没有更新,怎么写逻辑从数组中删除此对象

回复
阅读 1.5k
4 个回答
✓ 已被采纳

这题肯定不能用数组遍历做。太恐怖了,建议你维护个额外队列,把搜索这块做成 n(1)

// 你维护的数据
list1 = []

// 判断存在位置的数据
hash1 = {
    // key 是name
    // value 是下标
    key: value
}

这样你做的时候只需要判断 hash 里面有没有就完事了,有的话就是更新。没有就是push并记录下标。


也不能说妥了,其实你可以在读的时候做,判断缓存过期就不读了。维护一个有序的队列。比如说最早的在最前面,定时做删除,这样就是 一个 while 判断。

list = [];
list._push = list.push;
list._hash = {};
list.push = function(item){
    let idx = this._hash[item.name];
    console.log(item, idx, this.length)
    if(idx === undefined){
        this._hash[item.name] = this.length
        this._push(item);
    }else{
        this[idx] = item;
    }
}

list.push({name: 1, value: 0})
list.push({name: 2, value: 1})
list.push({name: 1, value: 2})
list.push({name: 3, value: 3})
console.log(list, list.length)

image.png

这个问题就是多定时器和单循环的选择问题了
1、多定时器,因为数组数量不定,多定时器会增加内存开销,可能会有内存泄漏的风险,所以不推荐
2、单循环,在循环中遍历数组从而更新数组,这里循环的间隔不宜过长,不然数组更新不及时,可以使用requestAnimationFrame,以下是实现:

let objArray;
// 这是添加Object的方法,给每个object增加time属性,记录add的时间
function addObject(obj) {
  obj.time = Date.now();
  const index = objArray.findIndex(i => i.name === obj.name);
  if (index > -1) {
    objArray[index] = obj;
  } else {
    objArray.push(obj);
  }
}
// 使用requestAnimationFrame不断遍历数组进行更新
function checkList() {
  objArray = objArray.filter(obj => {
    return Date.now() - obj.time < 6e3;
  });
  requestAnimationFrame(checkList);
}
// 启动遍历
checkList();

对于数据,想按 name 查找节点并替换之,可以用 findIndex 找到索引,再替换掉。如果数组中的数据较大,就不适合使用数据来遍历查找了,应该是使用 Map,不管是用 object map 还是用 Map 类都可以。

节点中可以保存一个时间数据,直接给节点这个数据,在加入的时候赋时间值就好。可以考虑使用 Proxy 自动注入 stamp。

而 6000 毫秒过期这个事情,不一定真的是要每 6 秒(或者更高频次)进行一次清理。只需要在使用数据的时候进行一次过滤就好。在缓冲区足够的情况下,每次使用数据的时候过滤出 6 秒内的数据就好。只有在达到一定时间(比如半分钟)或者一定空间的情况下,再触发清理。甚至如果使用的数据时只使用“单个”的情况下,都只需要把这个数据找出来判断是否过期就行,不需要过滤完了再来找。

其实从你的描述来说,这个问题可能还可以简化一下,因为无论name对应对象是否存在,其实你都需要push进去,因为需要更新时间,所以你其实可以考虑一个较长的先进先删的通道(实际上是有头部指针标记、尾部指针标记、搜索指针标记的 双向链表,或者环形数组),不停的向里面push,但查找时从尾部开始查找(找到最新push进去的值)。这样只需要提取值时看是否有效就好。
这样有一个好处就是,其实可以不主动删除,直到存满时,再触发一次删除超过6秒的(逆序搜索到第一个时间超过6秒的节点,头部指针直到其后即可)

其实要优化这个问题的解决方案,还需要题主真正给出这个数组完整的用途,因为数组用途(使用方法),对优化方向有特别大的影响。而不是简单的,靠题主现在简单的介绍(现在可能不完整、有些细节可能没有介绍到位)。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏