我无法弄清楚我是做错了什么,还是我只是努力推动它。
我正在尝试将来自我的在线数据库的约70000条记录与IndexedDB和EventSource同步到Worker。
所以每个包获得2000条记录,然后使用以下代码将它们存储在IndexedDB中:
eventSource.addEventListener('package', function(e) {
var data = JSON.parse(e.data);
putData(data.type, data.records);
});
function putData(storeName, data) {
var store = db.transaction([storeName], 'readwrite').objectStore(storeName);
return new Promise(function(resolve, reject) {
putRecord(data, store, 0);
store.transaction.oncomplete = resolve;
store.transaction.onerror = reject;
});
}
function putRecord(data, store, recordIndex) {
if(recordIndex < data.length){
var req = store.put(data[recordIndex]);
req.onsuccess = function(e) {
recordIndex += 1;
putRecord(data, store, recordIndex);
};
req.onerror = function() {
self.postMessage(this.error.name);
recordIndex += 1;
putRecord(data, store, recordIndex);
};
}
}
一切都适用于约10000条记录。没有真正测试限制在哪里。我怀疑在某些时候,并行的事务太多会导致单个事务非常慢,从而因为某些超时而导致问题。根据开发工具,70000记录约为20MB。
完成错误:
未捕获的TransactionInactiveError:无法执行'put' 'IDBObjectStore':交易已经完成。
有什么想法吗?
答案 0 :(得分:1)
我没有在代码中看到明显的错误,但您可以使其更简单,更快捷。我们无需等待上一个put()
成功发出第二个put()
请求。
function putData(storeName, data) {
var store = db.transaction([storeName], 'readwrite').objectStore(storeName);
return new Promise(function(resolve, reject) {
for (var i = 0; i < data.length; ++i) {
var req = store.put(data[i]);
req.onerror = function(e) {
self.postMessage(e.target.error.name);
};
}
store.transaction.oncomplete = resolve;
store.transaction.onerror = reject;
});
}
可能您看到的错误是因为浏览器对事务实施了任意时间限制。但同样,你的代码看起来是正确的,包括使用Promises(这对IDB来说很棘手,但据我所知,你能正确地做到这一点!)
如果仍然发生这种情况,我会在评论中使用独立的repro对浏览器提交错误。 (如果它在Chrome中发生,我很乐意看看。)
答案 1 :(得分:0)
我认为这是由于实施。如果您阅读规范,则事务必须保留事务中所有请求的列表。提交事务时,所有这些更改都会保留,否则事务将被中止。 Specs
可能是您的情况下1000请求的最大请求列表。您可以通过尝试插入1001条记录来轻松测试。所以我的猜测是,当达到1000请求时,事务被设置为不活动。
也许改变你的策略,只在每笔交易中提出1000个请求,并在完成另一个交易时开始新的交易。