Mon site Web contient un fichier JSON contenant des données destinées à être transférées dans IndexedDB local de mes utilisateurs. Je cherche un moyen de ne charger ce fichier JSON que lorsqu'une mise à jour est réellement nécessaire.
Pour clarifier, je prévois que mon site Web s'exécute presque entièrement à partir des données stockées localement de mes utilisateurs dans la mesure du possible, comme une application. Ils ne devraient avoir à télécharger le fichier JSON que lorsqu'une nouvelle mise à jour IDB est disponible.
Jusqu'à présent, j'ai essayé d'accomplir cela en exécutant l'événement onUpgradeNeeded
en tant que fonction asynchrone.
if (!window.indexedDB) { window.alert("Your browser doesn't support a stable version of IndexedDB, which is required for most functions of this website. For the best support, please use the latest version of Chrome, Firefox, or Safari."); } else { var dbVer = 39; //IDB Version (int only) var recipeObject; //instantiate global variable for module object import var recipeArray = []; //instantiate global array for module import var recipeDBver; //instantiate global variable for actual database version (TODO: implement version checking) var upgradeNeeded = false; var clearNeeded = false; var openRequest = indexedDB.open('recipeDatabase', dbVer); console.log("IDB.js running"); openRequest.onsuccess = function(e) { console.log('Running onSuccess'); }; openRequest.onerror = function(e) { console.log('Open Request ERROR'); console.dir(e); }; openRequest.onupgradeneeded = async function(e) { var db = e.target.result; console.log('Running onUpgradeNeeded'); db.onerror = function(errorEvent) { console.log("onUpgradeNeeded ERROR"); return; }; importObject = await import("/resources/recipeDB.js"); //TODO: remove debugging console.log('Module loaded'); console.log(importObject); recipeObject = importObject.default; console.log(recipeObject); recipeDBver = recipeObject.recipeDBver; console.log(recipeDBver); recipeArray = recipeObject.recipeArray; console.log(recipeArray); upgradeNeeded = true; if (!db.objectStoreNames.contains('drinks')) { var storeOS = db.createObjectStore('drinks', {keyPath: 'id'}); storeOS.createIndex('name', 'name', { unique: false }); storeOS.createIndex('type', 'type', { unique: false }); storeOS.createIndex('subtype', 'subtype', { unique: false }); storeOS.createIndex('tags', 'tags', { unique: false }); } else { clearNeeded = true; } console.log('IDB Upgrade Needed: ' + upgradeNeeded); console.log('IDB Clear Needed: ' + clearNeeded); db = e.target.result; if (clearNeeded == true) { clearData(); } else if (upgradeNeeded == true) { for (var i = 0; i < recipeArray.length; i++) { addItem(recipeArray[i]); } } }; function clearData() { var db = openRequest.result; var transaction = db.transaction(["drinks"], "readwrite"); var objectStore = transaction.objectStore("drinks"); var objectStoreRequest = objectStore.clear(); objectStoreRequest.onerror = function(e) { console.log('Error clearing data. ', e.target.error.name); console.dir(e); }; objectStoreRequest.onsuccess = function(e) { console.log('Data cleared successfully.') for (var i = 0; i < recipeArray.length; i++) { addItem(recipeArray[i]); } }; } function addItem(curItem) { var db = openRequest.result; var transaction = db.transaction(['drinks'], 'readwrite'); var store = transaction.objectStore('drinks'); var item = curItem; var request = store.add(item); request.onerror = function(e) { console.log('Error', e.target.error.name); console.dir(e); }; request.onsuccess = function(e) { console.log('Item added: ' + curItem.name); }; } }
La console renvoie ce qui suit:
Je suppose que l'événement onUpgradeNeeded
expire avant que le fichier JSON puisse se charger.
Existe-t-il un moyen de retarder le délai d'expiration? Sinon, est-ce que quelqu'un connaît une meilleure façon d'accomplir ce que j'essaie de faire?
3 Réponses :
Le gestionnaire d'événements onupgradeneeded doit se terminer de manière synchrone. Plus précisément, les demandes sur / dans la transaction de changement de version en cours d'exécution doivent être lancées dans le même tick de la boucle d'événements que lorsque la transaction de changement de version est lancée.
Cela ne ressort pas clairement de votre question, mais il semble que vous effectuez un appel asynchrone pour charger le json et attendez qu'il se charge, et cette attente qui se produit est ce qui permet à la transaction de changement de version de se terminer, et provoque toutes les demandes effectuées ensuite pour ne pas se produire dans le même tick de la boucle d'événements.
Le problème peut être vu à partir de ce que vous voyez dans la console. Tout d'abord, nous obtenons IDB.js est en cours d'exécution
, puis vous accédez à votre gestionnaire onupgradeneeded
, mais ensuite, au lieu d'avoir quoi que ce soit de cette console de fonction journalisé, nous voyons immédiatement le exécution du gestionnaire onsuccess
. La cause en est que vous avez défini votre gestionnaire onupgradeneeded
comme étant async
, ce qui signifie que cette fonction arrête essentiellement l’exécution à await import ("/ resources / recetteDB .js ");
ligne pendant qu'il attend la résolution de l'importation. Cela signifie essentiellement en ce qui concerne les événements de l'IDB que onupgradeneeded
est terminé et qu'il doit aller dans onsuccess
. Comme Josh le dit plus haut, c'est parce que onupgradeneeded
doit résoudre de manière synchrone .
Voici ce que vous pouvez faire pour contourner ce problème:
synchrone lors de la mise à niveau
C'est l'une des difficultés liées à l'utilisation d'IndexedDB: il n'est pas basé sur la promesse, donc l'utilisation des fonctions async
basées sur la promesse ne fonctionne pas toujours bien avec elle. Je trouve généralement que ces défauts nécessitent plus de code pour les gérer (comme l'utilisation d'appels .then ()
afin que je puisse avoir des gestionnaires d'événements synchrones tout en effectuant les activités asynchrones nécessaires).
Étape 1 : Utilisez les données json du package javascript.
Étape 2 : Utilisez importScript ()
dans l'événement de mise à niveau.
Étape 3 : Exécutez votre script indexedDB avec Worker
.