Last active
May 7, 2018 18:14
-
-
Save mshwery/abb46d8cd85a59e65bf8 to your computer and use it in GitHub Desktop.
a localStorage wrapper with time-to-live and JSON stringify/parsing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* store.js | |
* a localStorage wrapper with time-to-live and JSON stringify/parsing | |
* | |
* @author Matt Shwery | |
* @license MIT (http://www.opensource.org/licenses/mit-license) | |
*/ | |
store = (function () { | |
// polyfill for localstorage into stale storage so this data store doesnt ever fail | |
if (!('localStorage' in window)) { | |
//if (!Modernizr.localstorage) { | |
window.localStorage = { | |
_data: {}, | |
setItem: function (id, val) { return this._data[id] = String(val); }, | |
getItem: function (id) { return this._data.hasOwnProperty(id) ? this._data[id] : undefined; }, | |
removeItem: function (id) { return delete this._data[id]; }, | |
clear: function () { return this._data = {}; } | |
}; | |
} | |
var PREFIX = 's'; | |
// prefixes the key with the store.js prefix | |
function prefix(key) { | |
return PREFIX + ':' + key; | |
} | |
// returns the current time in milliseconds | |
function now() { | |
return +new Date(); | |
} | |
// returns the value associated with the given key, if it exists | |
// returns null if the key doesn't exist | |
function getItem(key) { | |
var item = localStorage.getItem(key); | |
if (item) { | |
try { | |
item = JSON.parse(item); | |
} catch (err) { | |
console.warn(err); | |
} | |
} | |
return item; | |
} | |
// saves a new key/value pair if the key doesn't exist, otherwise | |
// updates the value | |
function setItem(key, value) { | |
var valueString = value; | |
try { | |
valueString = JSON.stringify(valueString); | |
} catch (err) { | |
console.warn(err); | |
} | |
// try to set the item in localStorage | |
// if the attempt failed then this block executes | |
if (!trySetItem(key, valueString)) { | |
// try to remove expired stuff | |
removeExpiredItems(); | |
// try again and return the item regardless of failure | |
trySetItem(key, valueString); | |
} | |
// either way, return the original value, not the stringified one | |
return value; | |
} | |
function trySetItem(key, value) { | |
try { | |
localStorage.setItem(key, value); | |
return true; | |
} catch (e) { | |
return false; | |
} | |
} | |
// removes expired items from cache | |
function removeExpiredItems() { | |
// get localStorage keys as array | |
// filter out only ones that include our localStorage PREFIX | |
var items = Object.keys(localStorage).filter(belongsToCache); | |
items.forEach(getItemOrExpire); | |
} | |
function getItemOrExpire(key) { | |
var item = getItem(key); | |
// if there's a expired ttl, remove the item | |
if (item && item.ttl && ttlIsExpired(item.ttl)) { | |
return removeItem(key); | |
} | |
return item; | |
} | |
function ttlIsExpired(ttl) { | |
return ttl < now(); | |
} | |
function belongsToCache (key) { | |
return key.indexOf(PREFIX) !== -1; | |
} | |
// accepts optional ttl (in minutes) | |
function set(key, value, ttl) { | |
// add prefix to key | |
key = prefix(key); | |
// convert ttl from minutes to milleseconds | |
if (ttl != null) ttl = now() + (ttl * 60000); | |
// grab any previous items by this key | |
var oldItem = getItem(key); | |
// if the old item's ttl isn't expired and there's no ttl passed in use the old ttl | |
// this allows you to continue to update an object with new values without updating its expiry | |
// TODO: evaluate need for this | |
if (!ttl && oldItem && oldItem.ttl && oldItem.ttl >= now()) { | |
ttl = oldItem.ttl; | |
} | |
var item = { | |
value: value, | |
ttl: ttl | |
}; | |
return setItem(key, item); | |
} | |
function get(key) { | |
// add fs and user id prefix to key | |
key = prefix(key); | |
var item = getItemOrExpire(key); | |
// return the retrieved item's value if it exists, | |
// or if it was removed return the removal's return (undefined) | |
return (item && item.value) || item; | |
} | |
// remove an item from local storage | |
function removeItem(key) { | |
return localStorage.removeItem(key); | |
} | |
function remove(key) { | |
return removeItem(prefix(key)); | |
} | |
// delete all key/value pairs currently stored | |
function clear() { | |
// because we only want to delete stuff from localStorage that this function added, | |
// loop through them one by one and remove them if they have this function's PREFIX | |
for (var key in localStorage) { | |
// remove only cached stuff that contains our prefix | |
if (belongsToCache(key)) removeItem(key); | |
} | |
} | |
return { | |
get: get, | |
set: set, | |
remove: remove, | |
clear: clear | |
}; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment