简体   繁体   中英

IndexedDB when populating many ObjectStores, Error: Failed to execute 'transaction' on 'IDBDatabase': A version change transaction is running

The good @Josh has already answered an similar question regarding the error message when populating IndexedDB ObjectStores:

Failed to execute 'transaction' on 'IDBDatabase': A version change transaction is running

The answer is suited for the case of populating just one ObjectStore. However in my case, I need to populate at least 5 ObjectStores.

I can create and populate all ObjectStores by looping through a list which holds all data needed to create and populate each one. The script works fine, the majority of time, however I detected a flaw, so instead of working flawless, every time is executed, after some executions I receive the above message.

As stated in the answer the issue is related to execution timing. Based on the solution posted, I modified my code, in order to use the same transaction in all the process of creating and populating. However when executing, there is a new error:

Uncaught TransactionInactiveError: Failed to execute 'put' on 'IDBObjectStore': The transaction has finished.

And again @Josh is the one who solves.

How can I populate recently created ObjectStores flawlessly, without any of the previous errors? Here is the code:

 var db;
 function createPopulate(DB_NAME, DB_VERSION) {
   const datastores = [
   {osName:'a', osEndpoint:'/a', osKeyPath:'id',....},
   {osName:'b', osEndpoint:'/b', osKeyPath:'id',....},
   {osName:'c', osEndpoint:'/c', osKeyPath:'id',....}
   ];

   var request = indexedDB.open(DB_NAME, DB_VERSION);
   request.onupgradeneeded = function(e) {
     db = this.result;
     var tx = e.target.transaction;

     for (i in datastores) {
      // ObjectoStore created
      // Index created
      var customObjectStore = tx.objectStore(datastores[i].osName, "readwrite");
      popTable(customObjectStore, datastores[i].osEndpoint);
     }
  };

Inside the function, there is the popTable function, which gets the data and populates a given ObjectStore, using a fetch function, fetch API:

function poptable(parameter, endPoint) 
     fetchGet2(endPoint, populate, parameter);
        function populate(json, parameter) {
           for (var m in json) {
              parameter.add(json[m]);
           }
        }
}

When running the code, I receive this message:

  DOMException: Failed to execute 'add' on 'IDBObjectStore': The transaction has finished.

If the script is modified to execute the popTable only oncomplete event, the error message is:

  DOMException: Failed to execute 'objectStore' on 'IDBTransaction': The transaction has finished.   at IDBTransaction.objectStore.transaction.oncomplete.

How can I avoid those errors?

You can't keep a transaction open while you wait for other async things to happen, which is what you're doing in fetchGet2 . Transactions auto-commit whenever all requests are complete, which basically means if you have a request that you do not either synchronously make after opening the transaction or make in an event handler of one of those requests (which can be arbitrarily nested), then your transaction will commit before that request is ever executed.

You'll either have to do all your data fetching before writing anything to IndexedDB, or you'll have to use a separate transaction for each fetch.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM