在激活serviceworker时使用fetch创建indexeddb

时间:2018-04-21 23:46:27

标签: javascript service-worker indexeddb

我试图通过从服务器获取数据并在此示例后将其放入商店来创建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()
  );
 });

为什么第一个示例中的内容没有问题,而第二个示例中却没有?提前致谢。

1 个答案:

答案 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));
});