javascript - Pourquoi onsuccess est parfois appelé avant onupgradeneeded lors de la connexion à IndexedDB ?
J'ai des problèmes avec IndexedDB. Sur Firefox 18, lorsque je crée une nouvelle base de données, la méthode onsuccess est appelée en même temps que onupgradeneeded. Sur Chrome 24 (c'est le comportement que j'aimerais obtenir), la méthode onsuccess n'est appelée qu'après que la méthode onupgradeneeded a été complétée.
Selon les informations de MDN sur IndexedDB, j'avais l'impression que lorsque la méthode onsuccess était appelée, il était sûr de travailler avec la base de données, mais cela semble ne pas être le cas dans Firefox.
(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()
})();
Merci !
Réponse #1
Une des choses dont vous souffrez probablement est la fonctionnalité d'auto-validation dans IndexedDB. Si une transaction devient inactive pendant une courte période, elle validera la transaction et la fermera.
Dans votre cas, vous appelez une méthode asynchrone pour remplir les données, et c’est pourquoi la transaction devient probablement inactive. Si vous ajoutez un console.write après app.indexedDB.addDataFromUrl(o.name, o.data_source); vous verrez qu’il sera appelé avant que vos données ne soient récupérées, provoquant le commit de la transaction. C’est pourquoi les données ne sont pas présentes lorsque le callback de succès est appelé. Il est possible que le délai d’expiration des transactions soit plus long dans Chrome que dans Firefox. Cela n’est pas décrit dans la spécification, donc cela peut varier selon le fournisseur.
Au fait, si vous voulez ajouter des données dans votre appel Ajax, vous devrez également passer l'objet store en paramètre.
Réponse #2
faites ce que vous devez faire à l'intérieur de if( xhr.status == 200 ) {}, appelez une transaction depuis là, mettez les données dans l'objectStore et tout ce dont vous avez encore besoin
modifier :
Je le fais comme ça, ça fonctionne pour moi, la fonction oncomplete n'est appelée que lorsque toutes les données sont insérées et que l'objectStore est prêt à être utilisé :
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();
