在激活 serviceworker 时使用 fetch 创建 indexeddb
creating indexeddb using fetch while activating serviceworker
我正在尝试通过从服务器获取数据并将其放入存储中来创建索引数据库(此处使用 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()
);
});
为什么在第一个示例中一切正常,而在第二个示例中却不工作?提前致谢。
在第一个示例中,您没有调用异步函数,因此它每次都能正常工作。在第二个示例中,您正在调用一个异步函数 fetch,因此它总是会失败。您不能在 indexedDB 事件处理程序中使用异步函数。事件处理程序代码通常必须是同步的。
要解决此问题,请更改您安排异步代码的方式。换句话说,您需要重构为 fetch-connect-store,而不是执行 connect-fetch-store。这样,执行存储的打开处理程序在其函数体内没有异步调用。
明确地说,还有其他方法可以做到这一点,我只是向您建议一种可以避免所有问题的方法。如果你想要一种看起来仍然有点像你当前代码的骇人听闻的方式(我不建议这样做),那么它很简单。不要尝试在获取处理程序中重复使用 store
变量。 store
是 IDBObjectStore 的实例。商店的实例是有生命的,与创建它的交易相关联。您的交易与数据库相关联。如果没有发现请求,事务本身将超时。因为您在创建事务和使用事务创建放置请求之间有一个获取调用,所以事务超时,因为在正确的 window 时间(事件循环的相同滴答)内没有安排任何请求。因此,一个 hacky 的方法是创建事务,然后是存储,然后是 put 请求,所有这些都在 fetch 处理程序中。数据库连接此时仍将打开,因为它是一个页面生命周期变量,通常在关闭之前有效。同样,这不是编写良好的代码,也不是我认为非常好的方法,但它是可能的。此外,您在升级处理程序中执行所有这些操作,这也很糟糕,但无论如何请注意,您需要为此访问隐式事务而不是创建一个。
类似于:
//...
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));
});
我正在尝试通过从服务器获取数据并将其放入存储中来创建索引数据库(此处使用 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()
);
});
为什么在第一个示例中一切正常,而在第二个示例中却不工作?提前致谢。
在第一个示例中,您没有调用异步函数,因此它每次都能正常工作。在第二个示例中,您正在调用一个异步函数 fetch,因此它总是会失败。您不能在 indexedDB 事件处理程序中使用异步函数。事件处理程序代码通常必须是同步的。
要解决此问题,请更改您安排异步代码的方式。换句话说,您需要重构为 fetch-connect-store,而不是执行 connect-fetch-store。这样,执行存储的打开处理程序在其函数体内没有异步调用。
明确地说,还有其他方法可以做到这一点,我只是向您建议一种可以避免所有问题的方法。如果你想要一种看起来仍然有点像你当前代码的骇人听闻的方式(我不建议这样做),那么它很简单。不要尝试在获取处理程序中重复使用 store
变量。 store
是 IDBObjectStore 的实例。商店的实例是有生命的,与创建它的交易相关联。您的交易与数据库相关联。如果没有发现请求,事务本身将超时。因为您在创建事务和使用事务创建放置请求之间有一个获取调用,所以事务超时,因为在正确的 window 时间(事件循环的相同滴答)内没有安排任何请求。因此,一个 hacky 的方法是创建事务,然后是存储,然后是 put 请求,所有这些都在 fetch 处理程序中。数据库连接此时仍将打开,因为它是一个页面生命周期变量,通常在关闭之前有效。同样,这不是编写良好的代码,也不是我认为非常好的方法,但它是可能的。此外,您在升级处理程序中执行所有这些操作,这也很糟糕,但无论如何请注意,您需要为此访问隐式事务而不是创建一个。
类似于:
//...
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));
});