Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

localStorage unreliable in Firefox

I'm working on a deck building application for a card game I play. I'm using localStorage to save and retrieve decks. It seems to be working flawlessly in Chrome, but in Firefox it is working unreliably.

In FF, everything seems to work fine at first, the deck even persists through a reload. However, if I add a second deck and reload, it only finds the first deck. If I delete the first deck, it no longer finds anything.

All the local storage interaction is in scripts/vault.js, which I'll reproduce below. Am I doing something wrong?

vault = {};
vault.makeKey = function (s) {
    return "deck:" + s;
};
vault.friendlyName = function(s) {
    if (s.indexOf("deck:") === 0) {
        return s.substring(5);
    } else {
        return s;
    }
};
vault.store = function (deck, name) {
    if (!window.localStorage) {
        alert("This browser doesn't support local storage. You will be unable to save decks.");
        return;
    }
    var key = vault.makeKey(name);
    localStorage.setItem(key, deck.export());
};
vault.retrieve = function (key) {
    deck.import(localStorage[key]);
};
vault.getDecks = function () {
    var keys = Object.keys(localStorage),
        out = [],
        i,
        k,
        name = "";
    for (i = 0; i < keys.length; i++) {
        k = keys[i];
        name = vault.friendlyName(k);
        if (name !== k && localStorage[k]) {
            out.push({name: name, key: k});
        }
    }
    out.sort(function (a, b) {
        return a.name > b.name ? 1 : -1;
    });
    return out;
};
vault.deleteDeck = function (key) {
    localStorage.removeItem(key);
};

Basically, it seems like at some point the keys in localStorage get 'frozen' for lack of a better term; localStorage will behave correctly while I manipulate it, but as soon as I refresh the page it seems to revert to whichever state it got frozen in.

like image 844
Asmor Avatar asked Dec 13 '12 02:12

Asmor


People also ask

Does Firefox support local storage?

You can set up Firefox to always allow or block specific sites from storing information. You can also allow a site to store only for a single session. In the Cookies and Site Data section, click. Manage Exceptions….

Where is Firefox LocalStorage stored?

The DOM storage data is stored in the webappsstore. sqlite file in the profile folder. The profile folder is located in %APPDATA%\Mozilla\Firefox\Profiles\​ , named something like 321edcba. default , and within it, there's the webappsstore.

How long does LocalStorage last in browser?

LocalStorage has no expiration time, Data in the LocalStorage persist till the user manually delete it.


4 Answers

Posting this here to help anyone that may be experiencing what I am now experiencing.

If using Firefox, once you refresh the page, you need to close and re-open the dev tools in order to see the new localStorage items.

When the page refreshes, the localStorage items that were there before show. If you close and re-open the dev tools, you can see the new set. Any changes made from that point on (until the next refresh) will update live.

Definitely a Firefox dev tools bug.

I've reported the bug here: https://bugzilla.mozilla.org/show_bug.cgi?id=1706710

// Edit 5 minutes later I can't reproduce it now. I'm not sure but I think it might have been due to a Firefox update. It updated just as I'd finished writing the bug report. Did I really discover a bug in Firefox 87 that got fixed in Firefox 88 10 minutes before I updated?!! Will report back here if it re-occurs.

Animated gif of issue

like image 63
the_new_mr Avatar answered Oct 03 '22 03:10

the_new_mr


I have run into this same problem a few times and at first I didn't notice the reason why it just couldn't read the localStorage, but I think I found a solution for that.

The localStorage operations are all synchronous and different browsers have certain quirks about how they handle them.

In your case, the problem seems to be that you're trying to read the localStorage before the DOM is ready. I tried it with Firebug and I added a breakpoint to the beginning of the vault.js file and reload the page and when the code breaks, I check the dom-tab and find the localStorage property, and there it is - full list of stored values. When I removed the breakpoint and reloaded the page, they were all gone once the page was loaded.

This might be a bug in Firefox or other browsers just initialize the localStorage faster.

So, as a solution to your problem: try fetching the keys from localStorage AFTER the DOM is ready.

like image 21
jylauril Avatar answered Oct 03 '22 05:10

jylauril


Though this is an old post but thought my findings might help. I was also facing the same issue so I went through this post, tried this and this is what I have noticed, in firefox if you try to do anything (even a localStorage.getItem) with localstorage before window.load it will remove everything from it and you will not have anything. So whatever you want to do set or get, do it after window.load.

Something like this

$( window ).load(function() {
    //do whatever you want to do with localstorage
});

BTW I was trying to do some operations with localStorage at document.ready before this which was failing.

like image 31
Divya Gopal Avatar answered Oct 03 '22 04:10

Divya Gopal


jylauril is on the right track, I think.

I've been playing with delays, and noticing some odd behavior.

As far as I can tell, it seems like if you touch localStorage at all before ALL JavaScript has completed execution, including JS doing setTimeout, localStorage will appear blank for that pageview. For example:

$(window).load(function () {
    console.log("Waiting 10000ms", new Date());
    setTimeout(setDeckSelect, 10000);
});

Firebug's console:

Waiting 10000ms Date {Thu Dec 13 2012 10:35:48 GMT-0500 (Eastern Standard Time)}
exec.js (line 191)
getDecks Date {Thu Dec 13 2012 10:35:58 GMT-0500 (Eastern Standard Time)}
vault.js (line 23)
>>> localStorage
0 items in Storage 

I thought I might be on to something, but my theories so far have proven wrong. One weird thing I've noticed, though. Regardless of how long I wait, if I try to look up decks first, it will fail and local storage will be empty:

>>> vault.getDecks()
[]
>>> localStorage
0 items in Storage 

But if I do those in the opposite order...

>>> localStorage
8 items in Storage deck:dfs=
"{"identity":"MakingNews","cards":{}}", deck:ngrngfrn= "{"identity":"BuildingaBetterWorld","cards":{}}", deck:sdfgshsh= "{"identity":"MakingNews","cards":{}}", deck:sdfgdgdfg= "{"identity":"MakingNews","cards":{}}", deck:dfgdfgas= "{"identity":"EngineeringtheFuture","cards":{}}", deck:sdfsga= "{"identity":"MakingNews","cards":{}}", deck:gdgd= "{"identity":"MakingNews","cards":{}}", deck:gfsdfgsdfg= "{"identity":"BuildingaBetterWorld","cards":{}}"
>>> vault.getDecks()
[Object { name= "dfgdfgas",  key= "deck:dfgdfgas"}, Object { name= "dfs",  key= "deck:dfs"}, Object { name= "gdgd",  key= "deck:gdgd"}, Object { name= "gfsdfgsdfg",  key= "deck:gfsdfgsdfg"}, Object { name= "ngrngfrn",  key= "deck:ngrngfrn"}, Object { name= "sdfgdgdfg",  key= "deck:sdfgdgdfg"}, Object { name= "sdfgshsh",  key= "deck:sdfgshsh"}, Object { name= "sdfsga",  key= "deck:sdfsga"}]

If I log localStorage in the function, it works as well:

vault.getDecks = function () {
    console.log(localStorage);
    var keys = Object.keys(localStorage),
        out = [],
        i,
        k,
        name = "";
    for (i = 0; i < keys.length; i++) {
        k = keys[i];
        name = vault.friendlyName(k);
        if (name !== k && localStorage[k]) {
            out.push({name: name, key: k});
        }
    }
    out.sort(function (a, b) {
        return a.name > b.name ? 1 : -1;
    });
    return out;
};

it works. If I void it, though...

vault.getDecks = function () {
    // console.log(localStorage);
    void localStorage;
    var keys = Object.keys(localStorage),
        out = [],
        i,
        k,
        name = "";
    for (i = 0; i < keys.length; i++) {
        k = keys[i];
        name = vault.friendlyName(k);
        if (name !== k && localStorage[k]) {
            out.push({name: name, key: k});
        }
    }
    out.sort(function (a, b) {
        return a.name > b.name ? 1 : -1;
    });
    return out;
};

It does not work. It also doesn't work if I remove the void keyword and just have localStorage on its own as a statement.

I don't know why, but console.log(localstorage) does seem to fix this, and I can call the localStorage whenever I want.

Really freaking weird.

EDIT: I found a slightly better solution. Calling the 'length' attribute of localStorage works as well.

vault.getDecks = function () {
    //Weird hack to make FF load localStorage correctly...
    localStorage.length;
    var keys = Object.keys(localStorage),
        out = [],
        i,
        k,
        name = "";
    for (i = 0; i < keys.length; i++) {
        k = keys[i];
        name = vault.friendlyName(k);
        if (name !== k && localStorage[k]) {
            out.push({name: name, key: k});
        }
    }
    out.sort(function (a, b) {
        return a.name > b.name ? 1 : -1;
    });
    return out;
};

This is a bit better in that it doesn't log anything...

like image 44
Asmor Avatar answered Oct 03 '22 05:10

Asmor