IndexedDB при заполнении многих ObjectStores, ошибка: не удалось выполнить «транзакцию» в «IDBDatabase»: выполняется транзакция изменения версии

Хороший @Josh уже ответил на аналогичный вопрос относительно сообщения об ошибке при заполнении ObjectStores IndexedDB:

Не удалось выполнить "транзакцию" в "IDBDatabase": изменение версии транзакция выполняется

Ответ подходит для случая заполнения только одного ObjectStore. Однако в моем случае мне нужно заполнить как минимум 5 ObjectStore.

Я могу создать и заполнить все ObjectStore, прокручивая список, содержащий все данные, необходимые для создания и заполнения каждого из них. Скрипт работает нормально, большую часть времени, однако я обнаружил недостаток, поэтому вместо того, чтобы работать безупречно, каждый раз выполняется, после некоторых выполнений я получаю вышеуказанное сообщение.

Как указано в ответе, проблема связана со временем выполнения. Основываясь на опубликованном решении, я изменил свой код, чтобы использовать одну и ту же транзакцию во всем процессе создания и заполнения. Однако при выполнении возникает новая ошибка:

Uncaught TransactionInactiveError: не удалось выполнить "поместить" в "IDBObjectStore": транзакция завершена.

И снова @Josh решает.

Как я могу безошибочно заполнить недавно созданные ObjectStores без какой-либо из предыдущих ошибок? Вот код:

 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);
     }
  };

Внутри функции есть функция popTable, которая получает данные и заполняет данный ObjectStore, используя функцию выборки, fetch API:

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

При запуске кода я получаю это сообщение:

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

Если сценарий изменен для выполнения события popTable only oncomplete, появится сообщение об ошибке:

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

Как я могу избежать этих ошибок?


person digitai    schedule 22.02.2017    source источник


Ответы (1)


Вы не можете держать транзакцию открытой, пока ждете, пока произойдут другие асинхронные действия, что вы и делаете в fetchGet2. Транзакции автоматически фиксируются всякий раз, когда все запросы завершены, что в основном означает, что если у вас есть запрос, который вы либо не выполняете синхронно после открытия транзакции, или делаете в обработчике событий одного из этих запросов (который может быть произвольно вложенными), тогда ваша транзакция будет зафиксирована до того, как этот запрос когда-либо будет выполнен.

Вам либо придется выполнять выборку всех ваших данных, прежде чем что-либо записывать в IndexedDB, либо вам придется использовать отдельную транзакцию для каждой выборки.

person dumbmatter    schedule 28.02.2017
comment
Спасибо, ваш ответ ясен, что вы думаете об использовании синхронизации, скажем, с использованием старого XHR? - person digitai; 28.02.2017
comment
Это будет работать, но синхронизация означает блокировку, поэтому это плохо скажется на производительности. Если вы делаете все это в веб-воркере, я думаю, все будет в порядке. Но если возможно, было бы лучше просто не делать другие асинхронные действия, пока транзакция открыта. Либо используйте несколько транзакций, либо реорганизуйте свой код, чтобы другие асинхронные вещи выполнялись до начала транзакции. - person dumbmatter; 03.03.2017