异步使用 IndexedDB

Posted

技术标签:

【中文标题】异步使用 IndexedDB【英文标题】:Using IndexedDB asynchronously 【发布时间】:2017-05-25 23:30:48 【问题描述】:

加载数据并将它们存储在 indexeddb 数据库中。定期我的数据库崩溃并失去对它的访问权限。 请给我一个如何异步使用 indexeddb 的解决方案!

我现在使用的示例代码:

var dataTotal = 0;
var threads = 6;

//openIndexeddbConnection();

function start(total)

dataTotal = total;
  for (var i = 0; i < threads; i++) 
    loadData(i);
  


function loadData(dataNum)
  var dataNext = dataNum + threads;
  if(dataNext > dataTotal)
    //checkEnd();
    return;
  

  $.ajax(
    url: baseUrl,
    data: offset: dataNum,
    success: function (data) 
      successData(dataNext, data);
    ,
    type: 'GET'
  );


function successData(dataNext, data)
  var dataArray = data.split(';');

  saveData(dataArray);

  loadData(dataNext);


function saveData(dataArray)

  putItem();
  function putItem(i) 
    var count = i || 0;
    if(dataArray.length <= i)
      return;
    

    var transaction = Indexeddb.transaction([dataTableName], "readwrite");
    transaction.onsuccess = function (event) 
      //continue
      putItem(count);
    ;
    var objectStore = transaction.objectStore(dataTableName);

    var request = objectStore.add(data: dataArray[count++]);
  

【问题讨论】:

【参考方案1】:

您可以使用 Promise 将数据异步加载和保存到 indexedDB。下面是两个示例函数,用于将数据加载和保存到 indexedDB 中的简单对象存储。

从 indexedDB 异步加载:

function loadFromIndexedDB(storeName, id)
  return new Promise(
    function(resolve, reject) 
      var dbRequest = indexedDB.open(storeName);

      dbRequest.onerror = function(event) 
        reject(Error("Error text"));
      ;

      dbRequest.onupgradeneeded = function(event) 
        // Objectstore does not exist. Nothing to load
        event.target.transaction.abort();
        reject(Error('Not found'));
      ;

      dbRequest.onsuccess = function(event) 
        var database      = event.target.result;
        var transaction   = database.transaction([storeName]);
        var objectStore   = transaction.objectStore(storeName);
        var objectRequest = objectStore.get(id);

        objectRequest.onerror = function(event) 
          reject(Error('Error text'));
        ;

        objectRequest.onsuccess = function(event) 
          if (objectRequest.result) resolve(objectRequest.result);
          else reject(Error('object not found'));
        ;
      ;
    
  );

异步保存到 indexedDB:

function saveToIndexedDB(storeName, object)
  return new Promise(
    function(resolve, reject) 
      if (object.id === undefined) reject(Error('object has no id.'));
      var dbRequest = indexedDB.open(storeName);

      dbRequest.onerror = function(event) 
        reject(Error("IndexedDB database error"));
      ;

      dbRequest.onupgradeneeded = function(event) 
        var database    = event.target.result;
        var objectStore = database.createObjectStore(storeName, keyPath: "id");
      ;

      dbRequest.onsuccess = function(event) 
        var database      = event.target.result;
        var transaction   = database.transaction([storeName], 'readwrite');
        var objectStore   = transaction.objectStore(storeName);
        var objectRequest = objectStore.put(object); // Overwrite if exists

        objectRequest.onerror = function(event) 
          reject(Error('Error text'));
        ;

        objectRequest.onsuccess = function(event) 
          resolve('Data saved OK');
        ;
      ;
    
  );

示例使用代码

var data = 'id' : 1, 'name' : 'bla';

saveToIndexedDB('objectstoreName', data).then(function (response) 
  alert('data saved');
).catch(function (error) 
  alert(error.message);
);

// Load some data
var id = 1;
loadFromIndexedDB('objectstoreName', id ).then(function (reponse) 
  data = reponse;
  alert('data loaded OK');
).catch(function (error) 
  alert(error.message);
);

【讨论】:

感谢您的回答。我计划将来使用干净的 Promise 或 rxjs。使用 Promise 可以更轻松地捕获错误。但我想让代码没有任何错误。另外,在示例中你每次打开一个新的 indxedDBbut 连接,但我只使用了一个。我认为我们应该使用类似并发模式:生产者和消费者 喜欢这个答案。这就是我需要的【参考方案2】:

我一直在使用idb - 一个简单的库,它用承诺包装了IndexedDB。这些使异步数据库操作更加更易于使用。

如果您的目标是 Chrome(或使用支持它们的转译器),您可以使用 asyncawait 来简化您的代码:

async function saveData(dataArray) 
    const db = await idb.open('YourDB', currentVersion, upgradeFunction);
    const tran = await db.transaction('StoreName', 'readwrite');
    const store = tran.objectStore('StoreName');

    // This will add the items sequentially
    for(let item of dataArray) 
        await store.add(data:item);
    

【讨论】:

感谢您的回答。 IDB 是一个有趣的库,但我认为使用 IndexedDB 我可以在没有不必要的包装器的情况下工作。这个库的另一个问题是它在 IndexedDB 阻塞时没有捕获错误。是的,我的目标是chrome,但我不想使用await,我的代码应该也可以在其他浏览器中运行,另外现在beta中的wait/asynch,并且运行缓慢。 @Greg - async/await 是即将到来的规范的一部分,它们并不比 Promise 慢,因为它们基本上只是执行该功能。使用 TypeScript,您可以使用它们,它们将转换为 IE 可以运行的东西。我认为您也可以使用 Babel,尽管我自己没有这样做。我不确定你说它不捕获错误是什么意思——这不是它应该做的,它所做的只是用承诺包装回调函数。您在自己的代码中使用 promise 的结果进行错误处理,或者将 await 包装在常规的 try catch 中。 可能你对等待/异步的看法是正确的,但通常在开始的新功能中没有优化。例如,原生 Promises 的效果比 Polifills 差。一个连接打开时会创建事件blocked,我们会尝试做更多的事情。而且我认为这个事件是在两个并发事务冲突时触发的。还有问题,如何避免这个错误。 @Greg promises 已经存在了一段时间 - 有一些框架使用 promisfy 模式(而不是new Promise(func, func)),因此闭包更少,并且总是比 ES6 规范原生的更快(但这样做他们不符合该规范)。我不确定这是否重要,因为它们之间的差异只是 IO 或网络访问所花费时间的一个很小的因素。我每次都会支付 1 毫秒的开销,而不必下载 Bluebird :-) 对于阻塞我还没有发现这是一个问题,但我为每个异步操作打开一个新连接,而不是在共享连接中创建多个并发异步操作。我打开多个并发连接没有问题,只要它们都是相同的版本。

以上是关于异步使用 IndexedDB的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin 协程Flow 异步流 ② ( 使用 Flow 异步流持续获取不同返回值 | Flow 异步流获取返回值方式与其它方式对比 | 在 Android 中使用 Flow 异步流下载文件 )

Kotlin 协程Flow 异步流 ② ( 使用 Flow 异步流持续获取不同返回值 | Flow 异步流获取返回值方式与其它方式对比 | 在 Android 中使用 Flow 异步流下载文件 )

visA异步锁怎么使用

tornado中使用异步(tornado底层是使用协程写异步代码!)

如何使用异步函数异步监听 Firestore 中的值?

C# 使用多个异步方法