Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LRU cache implementation in Javascript

Java has LinkedHashMap which gets you 99% there to an LRU cache.

Is there a Javascript implementation of an LRU cache, preferably from a reputable source, that is:

  1. understandable
  2. efficient (amortized O(1) get/put/delete)

? I've been searching on the web but couldn't find one; I thought I found one on Ajax Design Patterns but it glosses over the sendToTail() method and has O(n) performance (presumably, since the queue and associative array are split up).

I suppose I could write my own, but I've learned the hard way that reinventing the wheel for core algorithms can be hazardous to one's health :/

like image 638
Jason S Avatar asked Jun 15 '09 14:06

Jason S


People also ask

What is LRU cache in Javascript?

LRU stands for Least Recently Used. It is a cache eviction policy that allows one to identify which item in the cache hasn't been used for a long time. For example, let's say we have a cache of that has 4 slots for its size and we have 4 items: [red, green, white, blue] in the cache.

How LRU cache is implemented?

To implement an LRU cache we use two data structures: a hashmap and a doubly linked list. A doubly linked list helps in maintaining the eviction order and a hashmap helps with O(1) lookup of cached keys.

What is LRU cache NPM?

A cache object that deletes the least-recently-used items. Specify a max number of the most recently used items that you want to keep, and this cache will keep that many of the most recently accessed items. This is not primarily a TTL cache, and does not make strong TTL guarantees.

How do you cache Javascript?

You can cache a resource using three methods add , addAll , set . add() and addAll() method automatically fetches a resource, and caches it, whereas in set method we will fetch a data and set the cache. });});


1 Answers

Map should be O(1) in most implementations average case. Since Map keeps insertion order, adding a bit of code around it will get you a LRU and for most uses this should be plenty fast.

I needed a simple LRU cache for a small number of expensive operations (1 second). I felt better about copy-pasting some small code rather than introducing something external, but since I didn't find it I wrote it:

class LRU {     constructor(max = 10) {         this.max = max;         this.cache = new Map();     }      get(key) {         let item = this.cache.get(key);         if (item) {             // refresh key             this.cache.delete(key);             this.cache.set(key, item);         }         return item;     }      set(key, val) {         // refresh key         if (this.cache.has(key)) this.cache.delete(key);         // evict oldest         else if (this.cache.size == this.max) this.cache.delete(this.first());         this.cache.set(key, val);     }      first() {         return this.cache.keys().next().value;     } } 

Usage:

> let cache = new LRU(3) > [1, 2, 3, 4, 5].forEach(v => cache.set(v, 'v:'+v)) > cache.get(2) undefined > cache.get(3) "v:3" > cache.set(6, 6) > cache.get(4) undefined > cache.get(3) "v:3" 
like image 159
odinho - Velmont Avatar answered Oct 09 '22 15:10

odinho - Velmont