IndexedDB:调用onUpgradeNeeded时从JSON文件加载数据

时间:2019-05-06 03:29:05

标签: javascript indexeddb

我的网站有一个JSON文件,其中包含要转移到用户本地LocaledDB中的数据。我正在寻找一种仅在实际需要更新时才加载此JSON文件的方法。

为澄清起见,我计划让网站尽可能完全依靠用户本地存储的数据运行,类似于应用程序。只有在有新的IDB更新可用时,他们才需要下载JSON文件。

到目前为止,我已经尝试通过将onUpgradeNeeded事件作为异步函数运行来实现此目的。

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



}

控制台返回以下内容: Console screenshot

我假设onUpgradeNeeded事件在JSON文件能够加载之前已超时。

是否可以延迟超时?如果没有,有谁知道一种更好的方法来完成我想做的事情?

3 个答案:

答案 0 :(得分:0)

onupgradeneeded事件处理程序需要同步完成。更准确地说,与版本更改事务开始时一样,需要在事件循环的同一时刻启动正在运行的版本更改事务上/之内的请求。

您的问题尚不清楚,但看起来您正在进行异步调用以加载json并等待其加载,而这种等待发生的原因是允许versionchange事务完成并导致发出所有请求之后就不会在事件循环的同一时间出现。

答案 1 :(得分:0)

从控制台中可以看到问题。首先,我们得到IDB.js is running,然后进入onupgradeneeded处理程序,但是随后,没有记录该功能控制台中的任何内容,而是立即看到onsuccess处理程序运行。造成这种情况的原因是,您将onupgradeneeded处理程序定义为async,这意味着该函数实际上在等待导入解决的同时在await import("/resources/recipeDB.js");行处停止执行。从本质上讲,就IDB事件而言,onupgradeneeded已经完成,它需要进入onsuccess。如Josh所说,这是因为onupgradeneeded需要同步解决

要解决这个问题,您可以做的是:

  • 使onupgradeneeded同步
  • 更新您的IDB模式(创建新的对象存储和索引)
  • 导入数据,成功导入后,将其插入数据库中

这是使用IndexedDB的困难之一:它不是基于承诺的,因此使用基于承诺的async函数并不总是可以很好地使用它。我通常会发现这些缺点需要更多的代码来处理(例如使用.then()调用,以便我可以在拥有同步事件处理程序的同时仍进行必要的异步活动)。

答案 2 :(得分:0)

第1步:使用javascript包json数据。
步骤2:在升级活动中使用importScript()
步骤3:使用Worker运行indexedDB脚本。