Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 557
Hans Avatar asked Dec 13 '13 11:12

Hans


2 Answers

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.

like image 58
Schien Avatar answered Sep 23 '22 02:09

Schien


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.

like image 2
Dalorzo Avatar answered Sep 22 '22 02:09

Dalorzo