Ace
Ace

Reputation: 664

Am I loopy or is it localstorage...?

My goal: To clean up localstorage, by removing previously used items with a for loop.

Usually, I have a number of items, like so:

order-1356666288243 => {"cartID":2713329701836,"productName"...
order-1356666288243 => {"cartID":2713329701836,"productName"...

When I check how many items there are altogether, I get the correct zero-based amount:

console.log( localStorage.length );

Even when I do a for loop to write out the key and values, and console.log() a few other things, all is well:

for(var i=0, len=localStorage.length; i<=len; i++) {

    var key = localStorage.key(i);
    var value = localStorage[key];
    console.log(key + " => " + value);


        if(key != '' && key != null){

            console.log( key.indexOf('order-') );
            console.log(i + '. Key: ', key);

            if(key.indexOf('order-') != -1){
                console.log('The key to be removed is: ', key.toString());
                localStorage.removeItem(key.toString());
            }
       }

    console.log(i + ': ' + len);
}

Everything pretty much does what one would expect. However, this line executes only once when I run the script:

localStorage.removeItem(key);

or

localStorage.removeItem(key.toString());

In fact, I have to run the entire script as many times as there are items. So if I have, say 3 items, I need to run the loop 3 times to get rid of each item.

I'm perplexed: Where did I go wrong? All the console.log() stuff shows up 3 times (if I have 3 items and run the for loop once) . Out of despair, I even changed i < len to i >= len, but that doesn't solve the problem either.

Anyone?

Upvotes: 0

Views: 125

Answers (3)

Francis Avila
Francis Avila

Reputation: 31621

The problem is that you are modifying a collection while you are traversing it. Always be careful when you do this.

In this particular case, the length of localStorage changes when you remove an item, so you end up skipping items.

You should either traverse localStorage backwards (last item to first item), or better yet you should do this in two passes: one pass to collect the keys to remove, and another pass to remove them:

Object.keys(localStorage)
.filter(function(key){return key.indexOf('order-')===0})
.forEach(localStorage.removeItem, localStorage);

Or if you need this to work in IE8 or FF3.x:

var delkeys = [], key, i, len;
for (i=0,len=localStorage.length; i<len, key=localStorage.key(i); i++) {
    if (key.indexOf('order-')===0) {
        delkeys.push(key);
    }
}
for (i=0,len=delkeys.length; i<len, key=delkeys[i], i++) {
    localStorage.removeItem(key);
}

Upvotes: 2

freethejazz
freethejazz

Reputation: 2285

The loop should count down to prevent problems with deleted keys altering storage length. Try this for loop instead:

for( var i = localStorage.length; i--;){
//make sure to remove references to len in your code
}

Upvotes: 1

Ted Hopp
Ted Hopp

Reputation: 234795

I think the problem is that when you remove an item, it changes the length of the local storage. Try iterating from the length-1 down to 0 instead of from 0 up to the length. (By the way, the loop condition should have been i < len, not i <= len. With my suggestion, of course, it should be i >= 0.)

Upvotes: 2

Related Questions