Mar*_*hes 7 javascript arrays caching
如果我想要一个固定大小为N的数组,以便缓存最近的N个项目,那么一旦达到限制N,我将不得不在添加最新项目时删除最旧的项目.
注意:我不关心最新项目是否在数组的开头或结尾,只要项目按添加顺序删除即可.
显而易见的方法是:
push()和shift()(所以cache[0]包含最旧的项目),或unshift()和pop()(所以cache[0]包含最新的项目)基本理念:
var cache = [], limit = 10000;
function cacheItem( item ) {
// In case we want to do anything with the oldest item
// before it's gone forever.
var oldest = [];
cache.push( item );
// Use WHILE and >= instead of just IF in case the cache
// was altered by more than one item at some point.
while ( cache.length >= limit ) {
oldest.push( cache.shift() );
}
return oldest;
}
Run Code Online (Sandbox Code Playgroud)
但是,我读过有关内存的问题shift和unshift因为他们改变了数组的开头和其他移动周围的一切,但不幸的是,一个这些方法已被用来做这种方式!
QS:
结论
在对数据结构做了一些更多的研究之后(我从来没有在其他语言中编程,所以如果它不是Javascript的原生,我可能还没有听说过!)并在多个浏览器中进行大量基准测试,包括小型和大型数组以及大量的读/写,这是我发现的:
offset考虑).如果您打算使用此方法,我建议在GitHub上使用已经创建的这个循环缓冲区.我实际需要的是最近最少使用(LRU)地图(使用双向链表).现在,由于我没有在原始问题中指定我的额外要求,我仍然将Bergi的答案标记为该特定问题的最佳答案.但是,因为我需要知道我的缓存中是否已经存在一个值,如果是这样,将其标记为缓存中的最新项,我必须添加到我的循环缓冲区add()方法(主要是indexOf())的附加逻辑使它不再多效率高于'pop/unpush'方法.但是,在这些情况下,LRUMap的性能会使其他两个水中的水都爆炸!
总结一下:
copyWithin - 目前表现糟糕,没理由使用如果我有一个缓存最近N个项目的数组,一旦达到限制N,我将不得不删除最旧的,同时添加最新的.
你不是要在数组中复制东西,O(n)每次都会采取步骤.
相反,这是环形缓冲区的完美用例.只需保留列表的"开始"和"结束"的偏移量,然后使用该偏移量访问缓冲区并以其模数为其模数.
var cache = new Array(10000);
cache.offset = 0;
function cacheItem(item) {
cache[cache.offset++] = item;
cache.offset %= cache.length;
}
function cacheGet(i) { // backwards, 0 is most recent
return cache[(cache.offset - 1 - i + cache.length) % cache.length];
}
Run Code Online (Sandbox Code Playgroud)