Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
localStorageWrapper that silently fails (reports error to console) on write fail. This is one of the options to tackle Safari's zero quota of localStorage when in private mode.
/**
* A constructor for a wrapper class implementing the localStorage public interface
* (getItem, setItem, removeItem, key, clear) and some of our extensions
* (getObject, setObject, removeObject, getObjectEvenIfNull).
*
* The idea is to create global `localStorageWrapper` and `sessionStorageWrapper` variables,
* to be used instead of `localStorage` and `sessionStorage` (see below).
* This is because in Safari on iOS in private mode, localStorage has a quota of 0
* and always throws an exception when trying to save anything.
*
* Instead of wrapping all localStorage writes with a try-catch, it's better to
* use a wrapper class instead and silently fail when we can not save.
*
* Note that `localStorageWrapper` does not implement `.length` property of localStorage
* and instead exposes `.getLength()` method (we could have implemented `.length` using
* Object.defineProperty or get syntax, but this is not supported in IE8-).
*
* @param {Storage} underlyingStorage either localStorage or sessionStorage
* @return Object prototype of a wrapper class that passes the calls to underlyingStorage
* and fails silently on errors
*/
var StorageWrapperProto = function(underlyingStorage) {
return {
/////////////////////////////// WRAPPER OF NATIVE LOCALSTORAGE METHODS//////////////////////////////
key: function(n) {
return underlyingStorage.key(n);
},
clear: function() {
underlyingStorage.clear();
},
getItem: function(key) {
return underlyingStorage.getItem(key);
},
setItem: function(key, value) {
try {
underlyingStorage.setItem(key, value);
} catch (e) {
window.console.error("Error writing to the storage for key = " + key +
"! (this is expected in private mode in Safari)");
}
},
removeItem: function(key) {
underlyingStorage.removeItem(key);
},
/////////////////////////////// BELOW ARE OUR CURRENT EXTENSIONS ///////////////////////////////////
getLength: function() {
return underlyingStorage.length;
},
removeObject: function(key) {
this.removeItem(key);
},
setObject: function(key, value) {
if (value !== null) {
var json = JSON.stringify(value);
this.setItem(key, json);
}
},
getObject: function(key) {
var json = null;
json = this.getItem(key);
if (!isUndefined(json) && json != "") {
json = JSON.parse(json);
}
return json;
},
/*
* This is to be used when we don't care if something is null in local storage,
* we always want to have an object to store properties on it (this is to be used
* in code paths where we assumed that we will always retrieve proper thing from
* local storage, like user profile, while since Safari in private mode can not
* store anything, it always returns null entries whatever we ask for)
*/
getObjectEvenIfNull: function(key) {
return this.getObject(key) || {};
}
};
};
// this requires `Object.create`; use polyfill if need to support old IEs
window.localStorageWrapper = Object.create(new StorageWrapperProto(window.localStorage));
window.sessionStorageWrapper = Object.create(new StorageWrapperProto(window.sessionStorage));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment