Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IE11 doesn't fire local storage events when value is too large

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?

like image 758
Mohoch Avatar asked Jan 15 '14 14:01

Mohoch


1 Answers

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.

like image 149
Mohoch Avatar answered Nov 15 '22 08:11

Mohoch