localStorage unreliable in Firefox

2019-04-26 21:39发布

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.

4条回答
趁早两清
2楼-- · 2019-04-26 21:57

• To ensure that localStorage data is made available consistently in all html pages: o Domain (local context) must be same. o Make sure to keep the << script >> tags identical in all Html files, o (Firefox only) make sure the onPageLoad is kept identical in all JavaScript files (added within html files), i.e. make sure to add same functions to PageLoadEvent.

查看更多
男人必须洒脱
3楼-- · 2019-04-26 21:59

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.

查看更多
我命由我不由天
4楼-- · 2019-04-26 22:00

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.

查看更多
仙女界的扛把子
5楼-- · 2019-04-26 22:19

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...

查看更多
登录 后发表回答