How to work around IE11 localStorage events firing twice or not at all in iframes?
Asked Answered
A

2

41

I'm guessing it's a bug, but I haven't been able to find any discussion about this.

It's known that IE10 will (against spec) fire storage events locally (ie, within the same global execution context from which the event was triggered), but IE11 seems to stray even further from the spec (http://www.w3.org/TR/webstorage/) when it comes to same-domain iframes:

  • if the iframe is embedded in the page that triggered the storage event, the event will fire TWICE within that iframe.
  • if the iframe is embedded in a page that is different from that which triggered the storage event, the event will not fire at all within that iframe.
  • if the event is triggered from an iframe, it will fire TWICE locally and TWICE in any other iframe embedded in the same page, but not at all in iframes of other pages.

You can test this by opening the following link in two separate tabs: http://hansifer.com/main.html

Anyone have any insight on this quirkiness?

Last tested version: IE v11.0.9600.16476 (update 2016-08-13: apparently it's the "Update Version" that's relevant, not the "Version" as reported in IE's About dialog)

Link to bug report: https://connect.microsoft.com/IE/feedback/details/811546/ie11-localstorage-events-fire-twice-or-not-at-all-in-iframes

UPDATE 2015-10-26

I just noticed that this seems to be fixed in v11.0.9600.18059, although I can't tell when the fix dropped since it doesn't seem to be referenced in any recent KB.

Unfortunately, IE11 localStorage events are still aberrant in other ways (although these are separate beefs from the issue set forth in this post):

  • IE raises localStorage events in the window context from which the localStorage set or remove that triggered the event was called. localStorage events should only be raised in foreign window contexts of the same origin. (update: working in EdgeHTML 13.10586)

  • IE uses empty string instead of null for e.oldValue/e.newValue when storage items are added/removed. (update: still a problem in EdgeHTML 13.10586)

  • IE calls localStorage event handler nondeterministically either BEFORE or AFTER set/remove takes effect instead of consistently AFTER.

UPDATE 2015-12-24

It appears this bug was carried over to Edge (tested EdgeHTML 13.10586)

UPDATE 2016-02-02

Welp, never mind. This bug is once again being observed in IE v11.63.10586.0 (update 2016-08-13: apparently it's the "Update Version" that's relevant, not the "Version" as reported in IE's About dialog)

UPDATE 2016-08-13

This now appears to be fixed in IE (Update Version 11.0.34), although storage events are still fired in the originating window, against spec (a known long-standing issue as mentioned above).

I found this KB that was included in the IE June 14, 2016 Security Update, although according to its description it only addresses the second bullet above.

As for Edge (tested EdgeHTML 14.14393), it seems also that this issue is now fixed, but there's a new problem: storage events are not firing across same-origin frames of the same page.

I reported it separately to MS here.

Aneroidograph answered 13/12, 2013 at 11:33 Comment(8)
+1 - I don't have an answer for you, but the bug is definitely legit (tested IE11). Very unusual. I get so irritated with everything that is broken in IE.Weatherley
@Aneroidograph You guys just wasting your time on connect.microsoft.com I have write a lot of bug but they never take care of them seriously. Even sometime crap is released in RTM. IE team is 2 step up. He never respond to a thread on connect until 1-2 year gone.Impatiens
The 'why' can only be answered by Microsoft people I'm afraid. Probably you should rephrase your question to ask for workarounds instead (or migitating factors, i.e. HTML elements or styles that may trigger the buggy behavior)Niko
"Just because I am an Internet Explorer"©Mala
IE has notoriously had problems with iframes triggering double loads, because the browser itself registers multiple body tags (which has triggered some very evil hacks and workarounds in the IAB/ad world for delivering ads in iFrames, most of which are "recommended" by MS). I haven't seen this myself yet, but my hunch would be if it is a native bug, that it has to do with the iframe instantiation and load operators causing the load event to double fire (once for parent body, once (or more) for iFrame body).Sarmentum
Comment to update: now local storage events not firing between same domain iframes, if they're inside other domain web page.Septenary
@Septenary Yep, you're right. I've updated the test site to highlight that. FYI, it's by origin, not domain.Aneroidograph
Added to bug: if the iframe is embedded in a page that is different from that which triggered the storage event, and the page is reloaded, it access to and old copy of the storageShaveling
C
3

If you ever want to throttle an event from being called multiple times, regardless the cause for invocation, use a flag to block subsequent events. There are several strategies:

.1. time-based throttling. suppose you have a function "func", and you'd like it to be called only once within 200ms:

function func(){
  if (document.func_lock) return;
  document.func_lock=true; // block future calls
  setTimeout(function(){document.func_lock=null;},300);
}

When multiple events are fired at the same time, you can expect all of them arrive within the 300ms window. The above code can be simplified by taking advantage of the timer handle:

function func(){
  if (document.func_lock) return;
  document.func_lock=setTimeout(function(){return;},300);
}

When the timer expires, the lock is automatically removed.

.2. Remove the flag by using a callback. The process is trivial so I won't post sample code here.

In terms of flag placement, you can use any unique DOM object. Since I don't know the context of your application, I'll just use "document" here. You can also use hash keys that are particular to your application since you are already dealing with local storage. The concept is the same.

Chester answered 19/1, 2014 at 5:14 Comment(1)
I guess there would be a simpler way. The event storage provides the newValue and the OldValue. If it were my intention to use the "second execution control" function I would store "last newValue" and "last oldValue" to make sure the event is not executed consecutively call with those same values.Anvers
A
2

I was able to work around the issue by using window.parent to register the event in the iframe in this way:

Iframe page

var win = window.parent || window.opener || window;
win.addEventListener('storage', handleLocalStorageEvent, false);

function handleLocalStorageEvent(e) {
    console.log('IFRAME local storage event', e);

    var sdf = document.getElementById('sdf');
    sdf.innerHTML = sdf.innerHTML + 'Storage Event => (' + e.newValue + ')<br>';
}

Disclaimer: Please note that this solution is meant to fix(work around) IE11 issue. By any means it is intended or suggested that this applies to all browser.

Anvers answered 20/1, 2014 at 18:34 Comment(1)
The iframes that load foo.com might have parent windows on bar.com, but they should still be able to share localStorage. In that situation there's still no workaround.Reptilian

© 2022 - 2024 — McMap. All rights reserved.