javascript - Warum wird onsuccess manchmal aufgerufen, bevor onupgradeneeded beim Verbinden mit IndexedDB aufgerufen wird?
Ich habe Probleme mit IndexedDB. Bei Firefox 18 wird die onsuccess-Methode aufgerufen, sobald ich eine neue Datenbank erstelle, gleichzeitig mit onupgradeneeded. Bei Chrome 24 (dies ist das Verhalten, das ich haben möchte) wird die onsuccess-Methode erst aufgerufen, nachdem die onupgradeneeded-Methode abgeschlossen ist.
Laut den MDN-Informationen zu IndexedDB hatte ich den Eindruck, dass es sicher ist, mit der Datenbank zu arbeiten, wenn die Methode onsuccess aufgerufen wird, aber das lässt es so aussehen, als sei es in Firefox nicht der Fall.
(function(){
app = {};
// These will hold the data for each store.
app.objectstores = [
{ name: 'UNIVERSITIES',
keyPath: 'UID',
autoIncrement: false,
data_source: 'http://mysites.dev/nddery.ca_www/larelance/data/universite.json' },
];
// Some information pertaining to the DB.
app.indexedDB = {};
app.indexedDB.db = null
app.DB_NAME = 'testdb';
app.DB_VERSION = 1;
/**
* Attempt to open the database.
* If the version has changed, deleted known object stores and re-create them.
* We'll add the data later.
*
*/
app.indexedDB.open = function() {
// Everything is done through requests and transactions.
var request = window.indexedDB.open( app.DB_NAME, app.DB_VERSION );
// We can only create Object stores in a onupgradeneeded transaction.
request.onupgradeneeded = function( e ) {
app.indexedDB.db = e.target.result;
var db = app.indexedDB.db;
// Delete all object stores not to create confusion and re-create them.
app.objectstores.forEach( function( o ) {
if ( db.objectStoreNames.contains( o.name ) )
db.deleteObjectStore( o.name );
var store = db.createObjectStore(
o.name,
{ keyPath: o.keyPath, autoIncrement: o.autoIncrement }
);
app.indexedDB.addDataFromUrl( o.name, o.data_source );
});
}; // end request.onupgradeneeded()
// This method is called before the "onupgradeneeded" has finished..??
request.onsuccess = function( e ) {
app.indexedDB.db = e.target.result;
app.ui.updateStatusBar( 'Database initialized...' );
// ***
// Would like to query the database here but in Firefox the data has not
// always been added at this point... Works in Chrome.
//
}; // end request.onsuccess()
request.onerror = app.indexedDB.onerror;
}; // end app.indexedDB.open()
app.indexedDB.addDataFromUrl = function( store, url ) {
var xhr = new XMLHttpRequest();
xhr.open( 'GET', url, true );
xhr.onload = function( event ) {
if( xhr.status == 200 ) {
console.log('*** XHR successful');
// I would be adding the JSON data to the database object stores here.
}
else{
console.error("addDataFromUrl error:", xhr.responseText, xhr.status);
}
};
xhr.send();
}; // end app.indexedDB.addDataFromUrl()
})();
Danke!
Antwort #1
Eines der Probleme, unter denen Sie wahrscheinlich leiden, ist die Auto-Commit-Funktionalität in IndexedDB. Wenn eine Transaktion für eine kurze Zeitspanne inaktiv wird, wird sie die Transaktion abschließen und sie schließen.
In Ihrem Fall rufen Sie eine asynchrone Methode auf, um die Daten zu füllen, und deshalb wird die Transaktion wahrscheinlich inaktiv. Wenn Sie ein console.write nach app.indexedDB.addDataFromUrl(o.name, o.data_source); hinzufügen, werden Sie sehen, dass es aufgerufen wird, bevor Ihre Daten abgerufen werden, was das Commit der Transaktion verursacht. Deshalb sind die Daten nicht vorhanden, wenn der Erfolgscallback aufgerufen wird. Es ist möglich, dass das Timeout für Transaktionen in Chrome höher ist als in Firefox. Es wird in der Spezifikation nicht beschrieben, sodass es je nach Anbieter variieren kann.
Übrigens, wenn du Daten in deinem Ajax-Aufruf hinzufügen möchtest, musst du auch das Objekt-Store als Parameter übergeben.
Antwort #2
Mache, was du innerhalb von if( xhr.status == 200 ) {} tun musst, rufe von dort eine Transaktion auf, lege die Daten in das ObjectStore und alles, was du sonst noch brauchst
bearbeiten :
Ich mache es so, funktioniert für mich, die oncomplete-Funktion wird erst aufgerufen, wenn alle Daten eingefügt sind und das Objekt-Store bereit zur Verwendung ist:
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://...", true);
xhr.addEventListener("load", function(){
if(xhr.status === 200){
console.info("Data received with success");
var data = JSON.parse(xhr.responseText);
var transaction = db.transaction([STORe],'readwrite');
var objstore = transaction.objectStore(STORE);
for(i = 0; i < data.length; i++){
objstore.put(data[i]);
};
transaction.oncomplete = function(event){
//do what you need here
console.info("Inserted data: " + data.length);
};
transaction.onerror = function(event){
};
transaction.onabort = function(event){
};
transaction.ontimeout = function(event){
};
transaction.onblocked = function(event){
};
};
}, false);
xhr.send();
