15

I have an application that uses localStorage events. One window writes to the storage an the other one reacts. This has been working fine for months, and still does on Chrome, FF and IE10, but since my users started using IE11 - it occasionally breaks.

After deep investigations I've discovered that IE11 fires the onstorage event only if the number of character in the new value is under a certain number (4282 by my measurements).
Furthermore, if there is already a value under the same key, IE will only fire the event if the size of both the old value and the new one together are under that limit.

One important note: in all cases the value does get written to the storage. The storage size is not exceeded in any stage.

This is a small code sample to demonstrate the issue:

<!DOCTYPE html>
<html>
<head>  
    <script type="text/javascript">

        function handle_storage(event)
        {
            alert("event fired!");
        }

        window.addEventListener("storage", handle_storage);

        var keyName = "keyName";

        function writeToStorage()
        {
            var num = parseInt(document.getElementById("bla").value);

            var customValue = "";
            for(var i = 0; i<num; i++)
                customValue+="c";

            localStorage.setItem(keyName, customValue);
        }               
    </script>
</head>
<body >
    <button onclick="writeToStorage()">Write</button>
    <input type="text" id="bla"/>
</body>
</html>

At first try it out with a small number - write 100 in the input and click the button. You will see the alert saying that the event had been fired.
Then try with a large number - 5000. You will see no alert.

Then try combinations of numbers, and you will see that each times the sum of both old and new value are over the limit - no event will be fired.

Is this a bug in IE11?
Am I missing something?
Is there any workaround?

Mohoch
  • 2,633
  • 1
  • 26
  • 26

2 Answers2

11

OK.

What we did in the end is a workaround. Ugly, but working.

After each insert to the storage, we also insert an "Insert Notification", which is just another item, with a predefined key. the value of the notification is the key of the actually modified item.

On the event handler of the 'storage' event, we retrieve the key from the newValue property of the event, and then retrieve the data itself from the storage using that key.

One very important thing to notice is that this flow might also get events of the actual data, in case IE11 thinks they are small enough. So we must make sure that we do not process any data retrieved directly through the event, but only what we get by the insert notifications.

Here is a simple code example that shows how you can do it, supporting IE11 and other browsers as well.

var _areInsertNotificationsEnabled; //set this to true if you are running in IE11
var _insertNotifcationsKey = "a_unique_key_for_insert_notifications";

function writeData (key, data)
{   
    localStorage.setItem(key, storageData);

    //If you are running in IE11, after adding the value itself, add an insert notification.
    //The notification's value should be the key of the actually modified value.
    if(_areInsertNotificationsEnabled)
        localStorage.setItem(_insertNotifcationsKey, key);
}

function onStorageChanged(event)
{
    //When waiting for insert notifications do not process the data itself,
    //so you won't mistakenly process the same data twice, in case the value 
    //was small enough for IE11 to fire the event
    if(!_areInsertNotificationsEnabled && event.key != _insertNotifcationsKey)
        processData(event.newValue);
    else handleInsertDataNotification(event);
}

function handleInsertDataNotification(event)
{
    //pull the actually modified key from the event
    var dataKey = event.newValue;
    //get the actually modified value
    var data = storage.getItem(dataKey);

    processData(data);        
}

function processData(data)
{
    //Do something smart
}

Hope this helps anyone.

Mohoch
  • 2,633
  • 1
  • 26
  • 26
  • I just ran into this exact problem and came up with a nearly identical solution before finding your post. I went searching though because it felt so hacky. I'm just glad to see I wasn't going crazy when the events weren't firing. – mag382 Apr 25 '14 at 20:09
  • @mag382, it is nice to feel you are not alone in this. We have this solution running on production for a few months now - and it's working great. – Mohoch May 08 '14 at 09:16
  • Thank you for discovering the character limit bug. – Motionharvest May 27 '15 at 16:41
  • I additionally noticed that there may be race conditions where Internet Explorer receives a storage event, yet querying for the updated local storage data returns *outdated* data. Delaying the "Insert Notification" by wrapping it in a 200 ms `setTimeout` solved this issue for me. – Abdull Nov 18 '19 at 16:58
0

I think you are reaching the maximum storage size limit and that is causing the described behavior.

What you describes sounds like the default behavior based on this test here:

http://dev-test.nemikor.com/web-storage/support-test/

Community
  • 1
  • 1
Dalorzo
  • 19,834
  • 7
  • 55
  • 102
  • 1
    that was the first thing I checked. But as I said, the data *is* getting written to the storage, and I can even write 10 times as much. It's just that I don't get the event when writing it. – Mohoch Jan 21 '14 at 15:47