Ketika ngirim foto cookies buat Moona-senpai terus dikira foto telur dadar... π
reine provides createSWR
, a simple in-memory caching helper based on the
stale-while-revalidate strategy:
// Assume that renderToString takes 1000 ms
const renderPage = createSWR(() => renderer.renderToString(app, ctx));
// Perform first rendering when preparing the server
await renderPage();
// Executed when the server receives requests
app.use(async () => {
// Returns immediately as long as the content is not old
const html = await renderPage();
return html;
});
It is ~500 bytes gzipped, has no dependencies, and can be used in Node.js or browser environment.
Pavolia Reine artwork by ι£―η°γ½γ‘
$ npm install @tkesgar/reine
The module exports a function createSWR
.
import createSWR from "@tkesgar/reine";
Wraps asyncFn
using stale-while-revalidate strategy into a new asynchronous
function.
Available options:
- maxAge (default:
1000
): the minimum age in miliseconds for the value to be considered stale. - staleAge (default:
2000
): the minimum age in miliseconds for the value to be considered old. - revalidateErrorHandler: an error handler that will be called with the
error if
asyncFn
throws an error when trying to revalidate (i.e. value is style). - initialValue: if a value is provided, it will be used as initial value.
The SWR instance will always start at
fresh
state.
const wrappedFetchData = createSWR(fetchData, {
maxAge: 30000,
staleAge: 60000,
revalidateErrorHandler(err) {
log.error({ err }, "Failed to fetch data from network; using stale data");
},
initialValue: null,
});
Returns the age of current value.
If the value is not available yet, the value will be Infinity
.
Returns the current state of value based on its age.
If no value is provided, sets the status to be "old", causing the next call to execute the function.
If a value is provided, sets the current value to the provided value and refreshes the cache.
Retrieves the value for the function. Depending on the status:
- If status is fresh, the currently available data will be returned. The function will not be executed.
- If status is stale, the currently available data will be returned.
However, the function will be executed and the value will be "refreshed".
- If the function throws an error and
revalidateErrorHandler
is available, it will be called with the error value as argument.
- If the function throws an error and
- If status is old, the function will be executed and the value is returned.
- If the function throws an error, the function will throws the error.
const fetchWinner = createSWR(() => fetchData("/api/user/winner/info"));
const winner = await fetchWinner();
console.log(await winner.username);
If there is no error handler, the error will be silently ignored; the SWR instance will return the stale value instead.
It is recommended to provide an error handler to some logging mechanism.
const fetchWinner = createSWR(() => fetchData("/api/user/winner/info"), {
revalidationErrorHandler(err) {
log.warn({ err }, "Failed to fetch winner info; using stale render result");
},
});
const winner = await fetchWinner();
console.log(await winner.username);
If an initial value is provided, the state will start as "fresh". This avoids the first call to be delayed.
const fetchWinner = createSWR(() => fetchData("/api/user/winner/info"), {
initialValue: { id: 323, username: "pavolia_reine" },
});
const winner = await fetchWinner();
console.log(await winner.username);
To avoid delays or errors for the first call, simply call the function first.
const fetchWinner = createSWR(() => fetchData("/api/user/winner/info"));
await fetchWinner();
const winner = await fetchWinner();
console.log(await winner.username);
It is possible to make preload non-blocking; however, be aware that the future call will throw error if the function throws error again.
const fetchWinner = createSWR(() => fetchData("/api/user/winner/info"));
fetchWinner().catch((err) => {
log.warn({ err }, "Failed to fetch winner info");
});
const winner = await fetchWinner();
console.log(await winner.username);
Setting maxAge
to 0
and staleAge
to Infinity
will cause the function to
always revalidate the value on every calls, but returns the stale value
instantly. This behaviour might be desirable if stale values are acceptable and
revalidation is "cheap".
const fetchWinner = createSWR(() => fetchData("/api/user/winner/info"), {
maxAge: 0,
staleAge: Infinity,
});
await fetchWinner();
const winner = await fetchWinner();
console.log(await winner.username);
The cache can be invalidated for certain use cases, such as receiving an update event for the cached resource.
const fetchWinner = createSWR(() => fetchData("/api/user/winner/info"), {
revalidateErrorHandler(err) {
log.warn({ err }, "Failed to fetch winner data");
},
});
externalService.on("match-finished", () => {
fetchWinner.reset();
});
To avoid delays, simply call the function after invalidating the cache.
externalService.on("match-finished", () => {
fetchWinner.reset();
fetchWinner().catch((err) => {
log.warn({ err }, "Failed to fetch winner data");
});
});
Alternatively, it is also possible to set the current value.
externalService.on("match-finished", (result) => {
fetchWinner.reset(result.winner);
});
No, createSWR
call returns a single wrapped function that will be executed
without arguments.
No, only in-memory.
Feel free to send issues or create pull requests.
Licensed under MIT License.