1.4.3 • Published 4 years ago

ngx-cacheable v1.4.3

Weekly downloads
8,998
License
ISC
Repository
github
Last release
4 years ago

Actions Status

ngx-cacheable

Observable/Promise cache decorator you can use to decorate class methods which return streams and cache their return values.

Installing (all examples below will also work with Promise-returning methods and the PCacheable, PCacheBuster decorators)

To install the package, just run

npm install ngx-cacheable

Import the decorator from ngx-cacheable like:

import { Cacheable } from 'ngx-cacheable';

and use it decorate any class method like:

@Cacheable()
  getUsers() {
    return this.http
    .get(`${environment.api}/users`);
  }

Now all subsequent calls to this endpoint will be returned from an in-memory cache, rather than the actual http call! Another example will be:

@Cacheable()
  getUser(id:string) {
    return this.http
    .get(`${environment.api}/users/${id}`);
  }

If we call this method by service.getUser(1), its return value will be cached and returned, up until the method is called with a different parameter. Then the old cache will be busted and a new one will take its place.

For more information and other configurations, see the configuration options below

Configuration

export interface ICacheConfig {
  /**
   * pass an Observable upon whose emission all caches will be busted
   */
  cacheBusterObserver?: Observable<void>;
  /**
   * @description request cache resolver which will get old and new paramaters passed to and based on those
   * will figure out if we need to bail out of cache or not
   */
  cacheResolver?: ICacheRequestResolver;
  /**
   * @description cache hasher which will be called to hash the parameters into a cache key
   */
  cacheHasher?: ICacheHasher;
  /**
   * @description cache decider that will figure out if the response should be cached or not, based on it
   */
  shouldCacheDecider?: IShouldCacheDecider;
  /**
   * maxAge of cache in milliseconds
   * @description if time between method calls is larger - we bail out of cache
   */
  maxAge?: number;
  /**
   * whether should use a sliding expiration strategy on caches
   * this will reset the cache created property and keep the cache alive for @param maxAge milliseconds more
   */
  slidingExpiration?: boolean;
  /**
   * max cacheCount for different parameters
   * @description maximum allowed unique caches (same parameters)
   */
  maxCacheCount?: number;
  /**
   * cache will be resolved asynchronously - an extra change detection pass will be made by
   * @description should cache be resolved asynchronously? - helps with declarative forms and two-way databinding via ngModel
   */
  async?: boolean;
}

Global Configuration

Some of the local cache config options (passed to specific decorators) can also be used as global ones. All the local configurations will of course take precedence over the global ones. Here are all the possible global configurations:

  /**
   * whether should use a sliding expiration strategy on caches
   * this will reset the cache created property and keep the cache alive for @param maxAge milliseconds more
   */
  slidingExpiration: boolean;
  /**
   * max cacheCount for different parameters
   * @description maximum allowed unique caches (same parameters)
   */
  maxCacheCount: number;
  /**
   * @description request cache resolver which will get old and new paramaters passed to and based on those
   * will figure out if we need to bail out of cache or not
   */
  cacheResolver: ICacheRequestResolver;
  /**
   * @description cache hasher which will be called to hash the parameters into a cache key
   */
  cacheHasher: ICacheHasher;
  /**
   * @description cache decider that will figure out if the response should be cached or not, based on it
   */
  shouldCacheDecider: IShouldCacheDecider;
  /**
   * maxAge of cache in milliseconds
   * @description if time between method calls is larger - we bail out of cache
   */
  maxAge: number;
  /**
   * @description storage strategy to be used for setting, evicting and updating cache.
   */
  storageStrategy: new () => IStorageStrategy | IAsyncStorageStrategy;
  /**
   * @description global cache key which will be used to namespace the cache.
   * for example, it will be used in the DOMStorageStrategy for now.
   */
  globalCacheKey: string;
  /**
   * @description a custom promise implementation. For example, if you use angularjs, you might like to provide $q's promise here change detection still works properly.
   */
  promiseImplementation: (() => PromiseConstructorLike) | PromiseConstructorLike;

Examples

Cache Busting

You can achieve it by decorating the cache busting method with the CacheBuster decorator. So you can have one method for fetching and caching data and another, to remove the cache. This is useful when for example you want to add an item to a list and refresh that list afterwards.

const cacheBuster$ = new Subject<void>();
export class Service {
  @Cacheable({
    cacheBusterObserver: cacheBuster$
  })
  getData() {
    ///needs to return an Observable
  }
  @CacheBuster({
    cacheBusterNotifier: cacheBuster$
  })
  saveData() {
    ///needs to return an Observable
  }
}

If you want to globally bust your whole cache (i.e caches of all Cacheable decorators), just import the globalCacheBusterNotifier and call next() on it, like:

import { globalCacheBusterNotifier } from 'ngx-cacheable';

globalCacheBusterNotifier.next();

Storage Strategies

By default, both the Observable and Promise decorators are caching in-memory only. Now, there's another browser-only caching strategy called DOMCachingStrategy which will use localStorage to persist the data. This means that you can simply provide that strategy somewhere up top in your application lifecycle to your decorators with a couple of lines:

import { GlobalCacheConfig } from 'ngx-cacheable'; 
import { DOMStorageStrategy } from 'ngx-cacheable'; 
GlobalCacheConfig.storageStrategy = DOMStorageStrategy;

And that's it, from then on, your decorators will be caching in localStorage and all other cache config options from above will just work. Also, you can specify the caching strategy on a decorator basis, so if you want a different strategy for one decorator only, just provide it via the cacheConfig object like:

@Cacheable({
    storageStrategy: customCachingStrategy
})

Creating your own strategy

It's also really easy to implement your own caching strategy, by extending the IStorageStrategy abstract class, which has this shape:

export abstract class IStorageStrategy {
  abstract getAll(cacheKey: string): Array<ICachePair<any>>;
  abstract add(entity: ICachePair<any>, cacheKey: string): void;
  abstract updateAtIndex(index: number, entity: ICachePair<any>, cacheKey: string): void;
  abstract removeAtIndex(index: number, cacheKey: string): void;
  abstract removeAll(cacheKey: string): void;
}

and then provide it to your decorators as in the example above.

For the PCacheable decorator, we also support async promise-based caching strategies. Just extend the IAsyncStorageStrategy and provide it to your promise decorators and voila. You can use that to implement Redis caching, IndexDB or whatever async caching you might desire.

IMPORTANT: Right now, we only support async strategies as a configuration for our promise decorators

Running the tests

Just run npm test.

Contributing

The project is open for contributors! Please file an issue or make a PR:)

Authors

1.4.3

4 years ago

1.4.2

4 years ago

1.4.2-beta.0

4 years ago

1.4.2-beta.1

4 years ago

1.4.1

4 years ago

1.4.0

4 years ago

1.4.0-beta.12

4 years ago

1.4.0-beta.10

4 years ago

1.4.0-beta.11

4 years ago

1.4.0-beta.9

4 years ago

1.4.0-beta.8

4 years ago

1.4.0-beta.7

4 years ago

1.4.0-beta.6

4 years ago

1.3.2

4 years ago

1.4.0-beta.5

4 years ago

1.4.0-beta.4

4 years ago

1.4.0-beta.3

4 years ago

1.4.0-beta.2

4 years ago

1.4.0-beta.1

4 years ago

1.4.0-beta.0

4 years ago

1.3.1

4 years ago

1.3.0

5 years ago

1.3.0-beta.0

5 years ago

1.2.9

5 years ago

1.2.8

5 years ago

1.2.7

5 years ago

1.2.5

5 years ago

1.2.5-beta.0

5 years ago

1.2.4

5 years ago

1.2.4-beta.2

5 years ago

1.2.4-beta.1

5 years ago

1.2.4-beta.0

5 years ago

1.2.3

5 years ago

1.2.2

5 years ago

1.2.1

5 years ago

1.2.1-beta.2

5 years ago

1.2.1-beta.1

5 years ago

1.2.0

5 years ago

1.1.9

5 years ago

1.1.8

5 years ago

1.1.7

5 years ago

1.1.7-beta.7

5 years ago

1.1.7-beta.6

5 years ago

1.1.7-beta.5

5 years ago

1.1.7-beta.4

5 years ago

1.1.7-beta.3

5 years ago

1.1.7-beta.2

5 years ago

1.1.7-beta.1

5 years ago

1.1.6

5 years ago

1.1.5

5 years ago

1.1.4

5 years ago

1.1.3

5 years ago

1.1.2

5 years ago

1.1.1

5 years ago

1.1.0

5 years ago

1.1.0-beta.1

5 years ago

1.1.0-beta

5 years ago

1.0.9

5 years ago

1.0.8

5 years ago

1.0.7

6 years ago

1.0.6

6 years ago

1.0.5

6 years ago

1.0.4

6 years ago

1.0.3

6 years ago

1.0.2

6 years ago

1.0.1

6 years ago

1.0.0

6 years ago