Skip to content

Instantly share code, notes, and snippets.

@MichalZalecki
Last active July 20, 2021 23:37
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save MichalZalecki/70a831304b0e83afbc0fbad3e8577068 to your computer and use it in GitHub Desktop.
Save MichalZalecki/70a831304b0e83afbc0fbad3e8577068 to your computer and use it in GitHub Desktop.
Simple sessionStorage/localStorage wrapper factory
import storageFactory from "./storageFactory";
export const localStore = storageFactory(localStorage);
export const sessionStore = storageFactory(sessionStorage);
/* ISC License (ISC). Copyright 2017 Michal Zalecki */
export function storageFactory(storage: Storage): Storage {
let inMemoryStorage: { [key: string]: string } = {};
const length = 0;
function isSupported() {
try {
const testKey = "__some_random_key_you_are_not_going_to_use__";
storage.setItem(testKey, testKey);
storage.removeItem(testKey);
return true;
} catch (e) {
return false;
}
}
function clear(): void {
if (isSupported()) {
storage.clear();
} else {
inMemoryStorage = {};
}
}
function getItem(name: string): string | null {
if (isSupported()) {
return storage.getItem(name);
}
if (inMemoryStorage.hasOwnProperty(name)) {
return inMemoryStorage[name];
}
return null;
}
function key(index: number): string | null {
if (isSupported()) {
return storage.key(index);
} else {
return Object.keys(inMemoryStorage)[index] || null;
}
}
function removeItem(name: string): void {
if (isSupported()) {
storage.removeItem(name);
} else {
delete inMemoryStorage[name];
}
}
function setItem(name: string, value: string): void {
if (isSupported()) {
storage.setItem(name, value);
} else {
inMemoryStorage[name] = String(value); // not everyone uses TypeScript
}
}
return {
getItem,
setItem,
removeItem,
clear,
key,
length,
};
}
@ZaLiTHkA
Copy link

just out of curiosity, wouldn't it be better to move the contents of isSupported out so it only runs once, rather than creating and then deleting __some_random_key_you_are_not_going_to_use__ at the start of every action?

for example:

function storageFactory(storage) {
  let inMemoryStorage = {}; 
  let browserStorageSupported;

  try {
    const key = "__some_random_key_you_are_not_going_to_use__";
    storage.setItem(key, key);
    storage.removeItem(key);
    browserStorageSupported = true;
  } catch (e) {
    browserStorageSupported = false;
  }

  function getItem(key) {
    if (browserStorageSupported) {
      return storage.getItem(key);
    }
    return inMemoryStorage[key] || null;
  }

  ...
}

@MichalZalecki
Copy link
Author

@MichalZalecki
Copy link
Author

@ZaLiTHkA Maybe, but I like function better than a "helper" variables.

@abereghici
Copy link

@ZaLiTHkA Maybe, but I like function better than a "helper" variables.

You can make isSupported function as closure and encapsulate that "helper' variable. In this way you won't write "some_random_key_you_are_not_going_to_use" key everytime when a function is called. Localstorage is synchronous and blocks the main thread.

@MichalZalecki
Copy link
Author

MichalZalecki commented Aug 26, 2020

To be strict, it's already in a closure, just not using variables outside its own function scope. Make it yours, adjust to your needs, if you have many reads/writes act accordingly. This was never my case and I don’t want to assume that if it worked once it’s going to work for each subsequent call. I imagine how the user can change settings during his visit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment