Read it like "Rock 'n' roll" or "Lock 'n' load"
This is a simple library that I initially wrote while working on a large AngularJS application. The goal is to make it easier to perform an async resource load and cache the result. It started as a simple aid to store user information for 10 minutes and then it became a corner stone of the project.
Being this useful I thought it was a pity not to make it public and available for modern JavaScript frameworks. Enough said, I decided to rewrite it from scratch and make it freely available.
As any other library this one solves a common problem: loading a resource and make it available for subsequent calls without calling the service again or impacting calling code. This is a typical problem when working with complex REST services. The following code is an example of what NOT TO DO.
var user;
function getUser() {
function loadUser() {
return fetch("/myself").then((u) => (user = u));
}
if (!user) {
loadUser();
}
return user;
}
The code above is loosely based on something I found in a production environment and have the following problems:
This library solves the above problems in a very easy-to-write way:
var user = new LoadNCache(() => fetch("/myself"));
function getUser() {
return user.get();
}
The LoadNCache object will take care of:
get()
method is called;.flush()
or due to the configured "autoflush");.catch()
the error multiple times from different callers;'after-load'
event.npm install --save @monesidn/load-n-cache
or
yarn add @monesidn/load-n-cache
and then you can:
import { LoadNCache } from "@monesidn/load-n-cache";
LoadNCache is a class that is only responsible for calling a "loadFunction" at the right moment and then store the returned value for the future. Each class instance can be configured to work in a different way so data can be stored using the right policy. The following are all examples of use cases that can be easily implemented using LoadNCache:
As the name suggests, it's a JavaScript function responsible for loading the data that are going to be stored. It may return a primitive value, an object or a promise, so also async functions are welcome. There are no constraints on how the value can obtained. The return value of the loadFunction is handled as follows
So when the loadFunction is called? Anytime a new value needs to be retrieved. This usually happen after a call to the .get() method if no cached value is available. If a persisted value is available it may happen that the loadFunction is never called.
Check out the gitpages! https://monesidn.github.io/load-n-cache/
As stated above when you want to allow your data to survive across page reloads you need to persist them. Out of the box this library provides only 2 very trivial strategies to achieve this result: localStorage
and sessionStorage
.
If you need to store "pure" JSON object not too large these two implementation may be enough. Many projects however will require a more complex approach, to solve this issue provide an implementation of "PersistenceManager". Below there is an example that
will use custom logic to retrieve objects from storage.
You can react to status changes listening to the following events:
This library was meant to have as few dependencies as possible. Currently at runtime it only depends on an EventEmitter implementation. I choosed not to use the node.js implementation because is not available on browsers. Also be sure that Promises are supported by your target platform both natively or using a polyfill.
Only promises fulfilled are persisted using the persistence manager. Rejected promises are not persisted by design. The main reason behind this choice is to make it easier to handle persistence errors. I can refactor the code to allow for storing refused promises but I can't see a useful use case right now. Let me know if you have a different opinion.
The autoflush time is measured starting at promise resolution or rejection. So if 5000ms are configured and promise resolution took 60000ms then the .flush() method will be called after 65000ms. Also remember that the autoflush may be subject to short delays due to JavaScript event queue.
I've created an angular 9 project to show what this library can do with few lines of codes. You can find it here:
class UserService {
constructor() {
this._user = new LoadNCache({
loader: () => fetch("/myself"),
autoFlushTime: 10 * 60 * 1000
});
}
getUser() {
return this._user.get();
}
}
class PrivilegeService {
constructor() {
this._roles = new LoadNCache({
loader: () => fetch("/roles"),
persistence: "localStorage",
persistenceKey: "security-roles"
});
}
hasRole(role) {
return this._roles.get().then((r) => !!r.find((i) => role === i));
}
}
function heavyJob() {
return new Promise((resolve) => setTimeout(resolve, 1000));
}
let heavyJobResult = new LoadNCache(heavyJob);
let result = await heavyJobResult.get();
class TimeService {
constructor() {
this._serverTime = new LoadNCache({
loader: () => fetch("/api/current-time").then((t) => new Date(parseInt(t))),
autoFlushTime: 50
});
}
getServerTime() {
return this._serverTime.get();
}
}
Generated using TypeDoc