2

I have created many, let's say three ObjectStores inside a defined and versioned IndexedDB schema.

I need to populate all of them. To do so, I created an object which stores both name end endpoint (where it gets data to populate). Also to avoid error when trying to fill objectstores already populated, I use the count() method to ... count key inside the objectstore and if there are 0 key, then populates, else reads.

It works perfect if I execute on a one by one basis, that is instead of using a loop, declare and execute each one of the three objectstores.

However when invoking the function to populate each storage inside a loop, I get the following error message for the last two objectstores to be populated:

Failed to read the 'result' property from 'IDBRequest': The request has not finished. at IDBRequest.counts.(anonymous function).onsuccess

Here is the code:

 // object contains oject stores and endpoints.
 const stores = [
 {osName:'user-1', osEndPoint:'/api/1,
 {osName:'user-2', osEndPoint:'/api/2},
 {osName:'user-3', osEndPoint:'/api/3}
 ]; 

 // open db.
 var request = indexedDB.open(DB_NAME, DB_VERSION);

 // in order to dynamically create vars, instantiate two arrays.
 var tx = [];
 var counts = [];
 var total = [];

 // onsuccess callback.
 request.onsuccess = function (e) {
    db = this.result;
    for(k in stores) {
      tx[k] = db.transaction(stores[k].osName).objectStore(stores[k].osName);
      counts[k] = tx[i].count();
      counts[k].onsuccess = function(e) {
        total[k] = e.target.result;

     // if the counting result equals 0,  then populate by calling a function that does so.
      if (total[k] == 0) {                 
          fetchGet2(stores[k].osEndPoint, popTable, stores[k].osName); //
       } else { 
           readData(DB_NAME, DB_VERSION, stores[0].osName);
           } 
        };
         }   // closes for loop
     }; // closes request.onsuccess.

The fetchGet2 function works well inside a loop, for example the loop used to create the objectstores, and also has been tested on a one by one basis.

It looks like an async issue, however I cannot figure how to fix the problem which is to be able to populate existing objectstores dynamically, avoiding to populate filled objectsores and only filling empty ones.

Indeed testing without the count issue, but inside the loop works perfect, or with the count but without loop.

At the moment and when logging counts[k], It only logs data for the last member of the object.

Thanks in advance, I'm coding with vanilla js, and I'm not interested in using any framework at all.

digitai
  • 1,870
  • 2
  • 20
  • 37
  • You're not by any chance using the variable `i` anywhere else in your code? As written, this is using a global `i` variable. If `fetchGet2` used `i`, for example, then `i` might be incremented and hence the request held in `counts[i]` is not the one that just fired the success event. Consider logging i within the onsuccess handler. Also, consider using `counts[i].onsuccess = function(e) {` and checking that `counts[i] === e.target.result` Your logic as presented here looks fine otherwise. – Joshua Bell Feb 13 '17 at 17:32
  • @JoshuaBell, I've tested changing the i var for k, indeed realized that no i is udes elsewhere in the namespace and also tested using counts[k].onsucceed = function(e) {}. However I get the same result: only executes the las element of the object, and when logging counts value and object name, only the last element is logged. – digitai Feb 14 '17 at 17:15

1 Answers1

2

Yes, this looks like an issue with async. For loops iterate synchronously. Try writing a loop that does not advance i until each request completes.

Josh
  • 17,834
  • 7
  • 50
  • 68
  • when iterating the loop without the count function, it works well, the problem is count (). – digitai Feb 13 '17 at 15:47
  • Thanks @Josh for the inspiration! A good simple effective example of such loop is provided here: https://stackoverflow.com/questions/14408718/wait-for-callback-before-continue-for-loop#answer-14408887 – Panini Luncher Jun 03 '18 at 02:21