服务工作者和IndexedDB

时间:2018-11-19 20:05:50

标签: service-worker

在一个简单的JavaScript Service Worker中,我想在事件发生之前拦截请求并从IndexedDB中读取一个值。respondWith

但是IndexDB的异步特性似乎不允许这样做。

由于indexedDB.open是异步的,因此我们必须等待它是好的。但是,回调(成功)稍后发生,因此该函数将在打开等待后立即退出。

我发现使其可靠运行的唯一方法是添加:

var wait = ms => new Promise((r, j) => setTimeout(r, ms));
await wait(50)

在我的readDB函数的末尾强制等待成功完成。

这完全是愚蠢的!

请甚至不要试图告诉我有关承诺的信息。在这种情况下,它们不起作用。

有人知道我们应该如何正确使用它吗?

样本readDB在这里(为清晰起见,删除了所有错误检查)。请注意,我们无法在成功内部使用await,因此不会等待两个内部IndexedDB调用!

async function readDB(dbname, storeName, id) {
    var result;
    var request = await indexedDB.open(dbname, 1); //indexedDB.open is an asynchronous function
    request.onsuccess = function (event) {
        let db = event.target.result;
        var transaction = db.transaction([storeName], "readonly"); //This is also asynchronous and needs await
        var store = transaction.objectStore(storeName);
        var objectStoreRequest = store.get(id); //This is also asynchronous and needs await
        objectStoreRequest.onsuccess = function (event) {
            result = objectStoreRequest.result;
        };
    };

    //Without this wait, this function returns BEFORE the onsuccess has completed
    console.warn('ABOUT TO WAIT'); 
    var wait = ms => new Promise((r, j) => setTimeout(r, ms));
    await wait(50)
    console.warn('WAIT DONE');
    return result;
}

1 个答案:

答案 0 :(得分:1)

  

请甚至不要试图告诉我有关承诺的信息。在这种情况下,它们不起作用。

...

...

...

我的意思是,尽管如此。假设您可以将event.respondWith()的基于承诺的IndexedDB查找放在 内,而不是放在{em> event.respondWith()之前。 (如果您想在调用event.respondWith()之前 进行此操作,以弄清您是否要做出回应,那是正确的,因为该决定是不可能的。是否同步调用event.respondWith()的问题。)

将IndexedDB封装在基于Promise的接口中并不容易,但是https://github.com/jakearchibald/idb已经完成了艰苦的工作,并且在服务工作者内部运行良好。此外,如果您只需要一个键/值对,而不是完整的IndexedDB功能集,https://github.com/jakearchibald/idb-keyval则使做这种事情变得更加容易。

下面是一个示例,假设您对idb-keyval没问题:

importScripts('https://cdn.jsdelivr.net/npm/idb-keyval@3/dist/idb-keyval-iife.min.js');

// Call idbKeyval.set() to save data to your datastore in the `install` handler,
// in the context of your `window`, etc.

self.addEventListener('fetch', event => {
  // Optionally, add in some *synchronous* criteria here that examines event.request
  // and only calls event.respondWith() if this `fetch` handler can respond.

  event.respondWith(async function() {
    const id = someLogicToCalculateAnId();
    const value = await idbKeyval.get(id);

    // You now can use `value` however you want.
    const response = generateResponseFromValue(value);

    return response;
  }())
});