Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safari fires StorageEvent in same tab

I am experiencing a strange issue in Safari (Version 13.1).

Use case: I am synchronizing data between various open tabs. This is implemented by writing to local storage and listening to the "storage" event.

According my understanding (and MDN: https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event), the storage event should be fired when something is written to local storage and two conditions are fulfilled:

  • the value for the item has changed
  • this change is originating from the same domain, but a different document (i.e. other tab/window)

In other words:

  • Let's say I have two open tabs (A and B)
  • Both listen for changes to "storage"
  • One of the tabs (A) writes something to local storage
  • Only the other tab (B) should receive the "storage" event

This works perfectly fine in Chrome, Firefox & Opera. But in Safari it is fired within the same tab as well.

This code will replicate this (works on any site in the console):

window.addEventListener('storage', event => console.log(event));
window.localStorage.setItem('foo', 'bar');
  • In Chrome/Firefox/Opera nothing will be logged (expected behavior)
  • In Safari, a storage event will be logged in the same window

In addition, the event itself does not seem to have sufficient information to identify which tab has triggered it. I am pondering to write another helper with a unique key per open tab and write that to local storage and listen for changes to it. But before I do that I wanted to see if I am missing something. I know there are some libraries to message other tabs, but I am reluctant to introduce a dedicated library for something as basic as this.

Question: Am I missing something? Is there a way to let the storage event in Safari only fire when something is written from other tabs?

like image 725
Christian Heine Avatar asked Apr 17 '20 10:04

Christian Heine


People also ask

When does the storage event of the window interface fire?

The storage event of the Window interface fires when a storage area (localStorage) has been modified in the context of another document. ... Log the sampleList item to the console when the storage event fires: window.addEventListener('storage', => { // When local storage changes, dump the list to // the console.

What is the key attribute of a storageevent?

A StorageEvent. Inherits from Event. Returns a string that represents the key changed. The key attribute is null when the change is caused by the storage clear () method. Returns a string with the new value of the key . This value is null when the change has been invoked by storage clear () method, or the key has been removed from the storage.

How do I use the event handler property onstorage?

In addition to the Window interface, the event handler property onstorage is also available on the following targets: Log the sampleList item to the console when the storage event fires: The same action can be achieved using the onstorage event handler property:

Is there a way to compare two tabs in localStorage?

You could also overwrite localStorage.setItem so that it fires in the current window in a similar way. Show activity on this post. Yes, you can generate unique id for each tab and compare them, look how this guy did here Another solution I found based on the same idea, generate and compare unique ids.. here Show activity on this post.


1 Answers

This also happens on IE11, as described here and here. The solution is to check, whether your current tab is in focus, as described here.

So, in your code:

function handler (event) {
  if (!document.hasFocus()) {
    // continue with your logic
  }
}
window.addEventListener('storage', handler);

I'd also suggest to handle the IE issue, in case your app needs it, as described in the above answers. You can do that by detecting the browser and enhancing the above logic.

like image 156
flaesh Avatar answered Oct 19 '22 18:10

flaesh