Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/lukeed/flru

A tiny (215B) and fast Least Recently Used (LRU) cache
https://github.com/lukeed/flru

Last synced: about 2 months ago
JSON representation

A tiny (215B) and fast Least Recently Used (LRU) cache

Awesome Lists containing this project

README

        

# flru [![Build Status](https://travis-ci.org/lukeed/flru.svg?branch=master)](https://travis-ci.org/lukeed/flru)

> A tiny (215B) and fast Least Recently Used (LRU) cache

Internally, two caches are kept. This is because it's far more performant to swap (and maintain) dictionaries than it is to `delete`/purge keys on every read/write interaction. Because of this, `flru` will store `2n` items in memory, where `n` is the [`max`](#max) limit. In practice, this means that with `max=3` and items `(a, b, c)` already written, writing a `d` value ***will not*** automatically purge the `a` key. Instead, `a` _can_ be retrieved, which would move it to the "active" cache. It's only when this "active" half exceeds the `max` that the "stale" half is purged.

> See [Usage](#Usage) for a visual explanation~!

This implementation is optimized for all-around performance – reads, writes, updates, and evictions.

This module is available in three formats:

* **ES Module**: `dist/flru.mjs`
* **CommonJS**: `dist/flru.js`
* **UMD**: `dist/flru.min.js`

## Install

```
$ npm install --save flru
```

## Usage

```js
// Legend:
// S => the stale cache
// A => the active cache

const flru = require('flru');

let cache = flru(3); // A=[] S=[]

cache.set('a', 1); // A=[a] S=[]
cache.set('b', 2); // A=[a,b] S=[]
cache.set('b', 9); // A=[a,b] S=[]
cache.set('c', 3); // A=[a,b,c] S=[]

cache.has('a'); //=> true

cache.set('d', 4); // A=[d] S=[a,b,c]
cache.get('a'); // A=[d,a] S=[a,b,c]
cache.set('e', 5); // A=[d,a,e] S=[a,b,c]
cache.get('a'); // A=[d,a,e] S=[a,b,c]
cache.get('c'); // A=[c] S=[d,a,e]

cache.has('c'); //=> true
cache.has('b'); //=> false
cache.has('a'); //=> true

cache.clear(); // A=[] S=[]
```

## API

### flru(max)
return `Object`

Initialize a new `flru` cache instance.

#### max
Required: `true`

Type: `Number`

Default: `1`

The maximum number of items to maintain – must be a positive, non-zero integer!

> **Important:** The default value is pointless and will result in excessive computation. It's there only to avoid memory leak!

### flru.has(key)
Return: `Boolean`

Check if the cache has the given key.

#### key
Type: `String`

The key name to check.

### flru.get(key)
Return: `Mixed`

Get the assigned value for a given key. Will return `undefined` if the cache has evicted `key` or never contained it.

#### key
Type: `String`

The item's unique name / identifier.

### flru.set(key, value)
Return: `undefined`

Persist an item to the cache by a given `key` name.

#### key
Type: `String`

The item's unique name / identifier.

#### value
Type: `Mixed`

The item's value to be cached.

### flru.clear(keepOld)
Return: `undefined`

Reset the cache(s) and counter.

#### keepOld
Type: `Boolean`

Default: `false`

When `true`, preserves the stale/outgoing cache.

> **Important:** This is used internally & generally should be ignored!

## Benchmarks

You can find benchmarks in the [`bench`]() directory. They are setup to run one library at a time so that there's no cross-contamination of memory management or Node's runtime caching.

* `set` – writing values into _new_ keys
* `update` – updating values into _existing_ keys
* `evict` – writing `2 * limit` keys to the cache, forcing eviction

> Results below are with Node v10.13.0

```
# set()
flru x 45,261 ops/sec ±1.63% (94 runs sampled)
lru-cache x 14,240 ops/sec ±5.70% (85 runs sampled)
tmp-cache x 8,229 ops/sec ±3.06% (83 runs sampled)
tiny-lru x 24,415 ops/sec ±2.48% (91 runs sampled)

# get()
flru x 78,585 ops/sec ±1.70% (98 runs sampled)
lru-cache x 27,409 ops/sec ±2.64% (93 runs sampled)
tmp-cache x 6,229 ops/sec ±1.06% (87 runs sampled)
tiny-lru x 20,313 ops/sec ±2.01% (96 runs sampled)

# has()
flru x 79,843 ops/sec ±1.35% (97 runs sampled)
lru-cache x 31,354 ops/sec ±2.87% (90 runs sampled)
tmp-cache x 813,828 ops/sec ±64.67% (95 runs sampled)
tiny-lru x 128,250 ops/sec ±3.73% (93 runs sampled)

# update()
flru x 44,885 ops/sec ±1.86% (95 runs sampled)
lru-cache x 15,616 ops/sec ±2.46% (94 runs sampled)
tmp-cache x 8,529 ops/sec ±0.85% (87 runs sampled)
tiny-lru x 23,060 ops/sec ±2.72% (93 runs sampled)

# evict()
flru x 8,258 ops/sec ±1.48% (88 runs sampled)
lru-cache x 1,492 ops/sec ±2.60% (77 runs sampled)
tmp-cache x 836 ops/sec ±0.59% (95 runs sampled)
tiny-lru x 2,626 ops/sec ±2.61% (81 runs sampled)
```

## Related

- [tmp-cache](https://github.com/lukeed/tmp-cache) - Full-featured (but slower) alternative, supporting time-sensitive expirations.
- [`tiny-lru`](https://github.com/avoidwork/tiny-lru) - Same as `tmp-cache` but significantly faster.

## License

MIT © [Luke Edwards](https://lukeed.com)