2017-02-22 9 views
1

Хорошая @Josh уже ответил на подобный вопрос относительно сообщения об ошибке при заполнении IndexedDB ObjectStores:IndexedDB при наполнении много ObjectStores, ошибка: Не удалось выполнить «сделку» на «IDBDatabase»: Операция изменения версия работает

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

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

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

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

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

И снова @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, используя функцию выборки, выборки 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 только OnComplete событие, сообщение об ошибке:

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

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

ответ

2

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

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

+0

Спасибо, ваш ответ ясен, как вы думаете, используя синхронизацию, скажем, используя старый XHR? – datelligence

+0

Это сработает, но синхронизация означает блокирование, поэтому было бы плохо для производительности. Если вы делаете все это в веб-работнике, я думаю, это может быть хорошо. Но если это возможно, было бы лучше просто не использовать другие асинхронные вещи, пока транзакция открыта. Используйте либо несколько транзакций, либо реорганизуйте свой код, чтобы другой асинхронный файл работал до начала транзакции. – dumbmatter