itz-caching-time
Version:
Cache your expensive code
104 lines (84 loc) • 2.56 kB
JavaScript
const Clock = require('./clock')
const Lock = require('itz-locking-time')
function memoryStorage () {
const storage = {}
return {
get: (key) => storage[key],
set: (key, val) => (storage[key] = val),
del: (key) => (delete storage[key])
}
}
module.exports = async ({ storage, storeAsString } = {}) => {
if (!storage) { storage = memoryStorage() }
const clock = await Clock({
set: async (key, val) => storage.set('e#' + key, storeAsString ? JSON.stringify(val) : val),
get: async (key, val) => storeAsString ? JSON.parse((await storage.get('e#' + key)) || 'null') : storage.get('e#' + key),
del: async (key) => storage.del('e#' + key)
}, id => storage.del(id))
const lock = Lock()
const main = {
set: async (key, value, ttl) => {
let newVal = {
v: value,
l: ttl ? Date.now() + ttl : 0
}
if (newVal.l) { clock.addEvent(newVal.l, key) }
if (storeAsString) { newVal = JSON.stringify(newVal) }
return storage.set(key, newVal)
},
get: async (key) => {
let res = await storage.get(key)
if (!res) { return null }
if (storeAsString) { res = JSON.parse(res) }
if (res.l && res.l <= Date.now()) {
await storage.del(key)
return null
} else {
return res.v
}
},
del: async (key) => {
return storage.del(key)
},
proxy: (fnc, { name, ttl, bgRefetch }) => {
return async (...a) => {
const key = name + 'Ω' + JSON.stringify(a)
const res = await main.get(name, true)
if (bgRefetch) {
if (!res) {
return lock.runOnce(key, async () => {
const res = {
expiry: ttl + Date.now(),
res: await fnc(...a)
}
await main.set(key, res, 0)
return res.res
}, true)
} else {
if (res.expiry >= Date.now()) {
lock.runOnce(key, async () => {
const res = {
expiry: ttl + Date.now(),
res: await fnc(...a)
}
await main.set(key, res, 0)
})
}
return res.res
}
} else {
if (!res) {
return lock.runOnce(key, async () => {
const res = await fnc(...a)
await main.set(key, res, 0)
return res
}, true)
}
return main.get(key)
}
}
}
}
return main
}