我试图通过从服务器获取数据并在此示例后将其放入商店来创建indexeddb(此处使用idb library)。
function createDB() {
idb.open('products', 1, function(upgradeDB) {
var store = upgradeDB.createObjectStore('beverages', {keyPath: 'id'});
store.put({id: 123, name: 'cheese', price: 10.99, quantity: 200});
store.put({id: 321, name: 'meat', price: 8.99, quantity: 100});
store.put({id: 222, name: 'sugar', price: 11.99, quantity: 300});
});
}
使用上面的示例一切正常,我看到存储在Indexeddb中的数据,但是当我将上面的示例修改为以下内容时,我发现数据的存储方式并不相同。
function createDB() {
idb.open('restaurants-reviews', 1, function(upgradeDB) {
let store = upgradeDB.createObjectStore('restaurants', { keyPath: 'id'});
fetch(`http://localhost:1337/restaurants`).then(response => response.json())
//.then(responses => {
// return Promise.all(responses.map(response => store.put(response)))
.then(responses => responses.map(response => store.put(response)))
});
}
稍后在serviceworker文件中,在两种情况下都会使用以下代码来激活serviceworker时创建数据。
self.addEventListener('activate', e => {
e.waitUntil(
createDB()
);
});
为什么第一个示例中的内容没有问题,而第二个示例中却没有?提前致谢。
答案 0 :(得分:1)
在第一个示例中,您没有调用异步函数,因此每次都可以使用它。在第二个例子中,您正在调用异步函数fetch,因此它总是会失败。您不能在indexedDB事件处理程序中使用异步函数。事件处理程序代码通常必须是同步的。
要解决此问题,请更改排列异步代码的方式。换句话说,您不想进行connect-fetch-store,而是想重构fetch-connect-store。这样,执行存储的on-open处理程序在其函数体中没有异步调用。
只是要非常清楚,还有其他方法可以做到这一点,我只是建议你一种避免所有问题的方法。如果你想要一种看似你当前代码的hackish方式(我不建议的话),那么它很简单。不要尝试在fetch处理程序中重用store
变量。 store
是IDBObjectStore的一个实例。商店的实例是生物,与创建它的交易相关联。您的交易与数据库绑定。如果没有请求,事务本身将超时。因为您在创建事务和使用事务创建put请求之间调用fetch,所以事务超时是因为没有在正确的时间窗口内调度请求(事件循环的相同滴答)。因此,一种hacky方式是在fetch hander中创建事务,然后是store,然后是put请求。 db连接仍将在此时打开,因为它是一个页面生命周期变量,通常在关闭之前有效。再次,这不是编写良好的代码,或者我认为非常好的方法,但它是可能的。此外,您在升级处理程序中执行此操作,这也很糟糕,但无论如何请注意您需要访问隐式事务而不是创建一个。
类似的东西:
//...
fetch(...).then(_ => {
// this might be wrong, you have to walk back to the transaction,
// it might be something like upgradeDB.source.transaction, I don't
// know, this is an obvious example of why you should be careful
// when using wrapper libraries, because here you need the
//IDBOpenRequest, not the IDBDatabase, but you don't have it
var txn = upgradeDB.transaction;
var store = txn.objectStore('restaurants');
responses.map(response => store.put(response));
});