异步使用 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(或使用支持它们的转译器),您可以使用 async
和 await
来简化您的代码:
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 异步流下载文件 )