Сервисные работники и IndexedDB - PullRequest
0 голосов
/ 19 ноября 2018

В простом сервисном сервисе JavaScript я хочу перехватить запрос и прочитать значение из IndexedDB перед событием .respondWith

Но асинхронная природа IndexDB, похоже, не позволяет этого.

Поскольку indexedDB.open является асинхронным, мы должны его дождаться, и это нормально. Однако обратный вызов (onsuccess) происходит позже, поэтому функция завершается сразу после открытия при ожидании.

Единственный способ убедить его в надежной работе - добавить:

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

в конце моей функции readDB, чтобы заставить ждать, пока не завершится успешное выполнение.

Это совершенно глупо!

И, пожалуйста, даже не пытайтесь рассказать мне об обещаниях. Они НЕ РАБОТАЮТ в этих обстоятельствах.

Кто-нибудь знает, как мы должны использовать это правильно?

Пример readDB находится здесь (для ясности удалена вся проверка ошибок). Обратите внимание, что мы не можем использовать await внутри onsuccess, поэтому два внутренних вызова 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 голосов
/ 21 ноября 2018

И, пожалуйста, даже не пытайтесь рассказать мне об обещаниях. Они НЕ РАБОТАЮТ в этих обстоятельствах.

...

...

...

Я имею в виду, они делают, хотя. Предполагая, что вы в порядке, поместите поиски IndexedDB на основе обещаний внутри из event.respondWith() вместо до event.respondWith(), по крайней мере. (Если вы пытаетесь сделать это до вызова event.respondWith(), чтобы выяснить, хотите ли вы вообще ответить, вы правы в том, что это невозможно, поскольку решение о том, стоит ли или не звонить event.respondWith() нужно сделать синхронно.)

Нелегко обернуть IndexedDB в интерфейс, основанный на обещаниях, но https://github.com/jakearchibald/idb уже проделал тяжелую работу, и он неплохо работает внутри сервисного работника. Более того, https://github.com/jakearchibald/idb-keyval делает это еще проще, если вам нужна только одна пара ключ / значение, а не полный набор функций IndexedDB.

Вот пример, если вы согласны с 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;
  }())
});
...