在一个简单的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;
}
答案 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;
}())
});