Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using indexeddb operation in multiple tabs

I am trying to save data from one tab to indexeddb and trying to get the data from another tab. But the operation is happening in second tab, only when i close the first tab or close the indexeddb in first tab using indexeddb.close();

How to get the data from indexeddb from other tabs(without closing the first tab or the indexeddb instance in the first tab)?

like image 634
Subramanian Vignesh Avatar asked Jul 31 '18 14:07

Subramanian Vignesh


People also ask

Is IndexedDB shared across tabs?

Data stored in indexedDB is available to all tabs from within the same origin.

Does IndexedDB persist between sessions?

Developers can leverage client storage mechanisms like IndexedDB to improve the user experience of their application by not only persisting state across sessions but also by decreasing the time it takes to load the initial state on repeat visits.

Is IndexedDB asynchronous?

Operations performed using IndexedDB are done asynchronously, so as not to block applications.

Is it safe to use IndexedDB?

The short answer is IndexedDB is vulnerable to malware and physical takeover attacks. It's better than many options because cryptography is done outside the browser execution environment, but it's not totally secure.


1 Answers

Data stored in indexedDB is available to all tabs from within the same origin. First clarify that both tabs point to the same origin.

However, indexedDB locks access to its data to essentially one tab at a time. If you have a connection to an indexedDB database open in one tab, and attempt to open a connection to the same database in a second tab, the second connection stalls, because it is blocked by the open connection in the other tab.

Notice that I say stalls, not fails. This is because the connection will eventually succeed (it becomes unblocked) once the tab that has the open connection closes the connection. The success event for the attempt to open the connection will eventually fire once it is unblocked.

The connection can be closed by calling IDBDatabase.prototype.close on the open connection, or by simply closing the tab.

One way to avoid some of the unwanted behavior and minimize how often a blocked event occurs is to avoid using a global database connection. By global I mean a database connection that you open some time near the time the tab is opened, when the dom is loaded and such, and then leave open for the remainder of the lifetime of the tab. Instead of opening a connection once for the entire lifetime of the tab, open a connection only when you need it, and then close it thereafter, and reopen a connection each additional time you need it, and close it thereafter. This way, the connection is closed for the majority of the time the tab is open, instead of being open for the majority of the time.

With all of that pretext, the answer to your question then is:

  1. In first tab, open a connection, write data, then close connection.
  2. Without closing first tab, then in second tab, open a connection, read data, then close connection.

Pay attention to the 'blocked' event. Add a listener in tab2 that listens for it. If you witness this event, then you tried to connect in tab2 while the tab1 connection was still open. Change your application to be able to react to this situation.

Here is simplistic example of listening for a blocked event:

function open(name, version, callback) {
  var request = indexedDB.open(name, version);
  request.onsuccess = function(event) {
    var db = request.result;
    callback(result, null);
  };
  request.onerror = function(event) {
    console.log('Failed to connect');
    callback(null, 'error');
  };
  request.onblocked = function(event) {
    console.log('Failed to connect because blocked');
    callback(null, 'blocked');
  };
}


open('foo', 1, function onopen(db, error) {
  if(error === 'error') {
    console.log('cannot do stuff because of error');
  } else if(error === 'blocked') {
    console.log('cannot do stuff because blocked');
  } else {
    console.log('do stuff with db', db.name);

    // do db operation here

    // cleanup when done
    db.close();
  }
});
like image 72
Josh Avatar answered Sep 21 '22 13:09

Josh