IndexedDB 的回调未在 Service Worker 的 'fetch' 事件中执行
IndexedDB's callbacks not being executed inside the 'fetch' event of a Service Worker
当应用程序向服务器请求新页面时,我正在尝试在服务工作者的 'fetch' 事件中的 IndexedDB 数据库中做几件事。这就是我的目标:
- 创建一个新的对象存储(它们需要根据'fetch'获取的数据动态创建);
- 在商店中存储一个元素。
或者,如果商店已经存在:
- 从商店获取元素;
- 更新元素并将其存储回商店。
问题是回调(onupgradeneeded、onsuccess 等)永远不会执行。
我一直在尝试使用彼此内部的回调,但我知道这可能不是最好的方法。我也试过在 'fetch' 上放置一个 event.waitUntil()
但它没有帮助。
'fetch'事件,调用函数registerPageAccess
的地方:
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request)
.then(function (response) {
event.waitUntil(function () {
const nextPageURL = new URL(event.request.url);
if (event.request.destination == 'document') {
if (currentURL) {
registerPageAccess(currentURL, nextPageURL);
}
currentURL = nextPageURL;
}
}());
/*
* some other operations
*/
return response || fetch(event.request);
})
);
});
registerPageAccess
,回调函数。
我知道代码很多,但只看第 5 行的 secondRequest.onupgradeneeded
。从来不执行,更不用说后面的了
function registerPageAccess(currentPageURL, nextPageURL) {
var newVersion = parseInt(db.version) + 1;
var secondRequest = indexedDB.open(DB_NAME, newVersion);
secondRequest.onupgradeneeded = function (e) {
db = e.target.result;
db.createObjectStore(currentPageURL, { keyPath: "pageURL" });
var transaction = request.result.transaction([currentPageURL], 'readwrite');
var store = transaction.objectStore(currentPageURL);
var getRequest = store.get(nextPageURL);
getRequest.onsuccess = function (event) {
var obj = getRequest.result;
if (!obj) {
// Insert element into the database
console.debug('ServiceWorker: No matching object in the database');
const addRes = putInObjectStore(nextPageURL, 1, store);
addRes.onsuccess = function (event) {
console.debug('ServiceWorker: Element was successfully added in the Object Store');
}
addRes.onerror = function (event) {
console.error('ServiceWorker error adding element to the Object Store: ' + addRes.error);
}
}
else {
// Updating database element
const updRes = putInObjectStore(obj.pageURL, obj.nVisits + 1, store);
updRes.onsuccess = function (event) {
console.debug('ServiceWorker: Element was successfully updated in the Object Store');
}
updRes.onerror = function (event) {
console.error('ServiceWorker error updating element of the Object Store: ' + putRes.error);
}
}
};
};
secondRequest.onsuccess = function (e) {
console.log('ServiceWorker: secondRequest onsuccess');
};
secondRequest.onerror = function (e) {
console.error('ServiceWorker: error on the secondRequest.open: ' + secondRequest.error);
};
}
我需要一种方法来执行 registerPageAccess
中的操作,其中涉及执行几个回调,但浏览器似乎在它们发生之前就杀死了 Service Worker。
Service Worker 内部的所有异步逻辑都需要基于承诺。因为 IndexedDB 是基于回调的,所以您会发现自己需要将相关的回调包装在 promise 中。
我强烈建议不要尝试自己执行此操作,而是使用以下库之一,这些库经过充分测试、高效且轻量级:
idb-keyval
,如果您不介意简单的键值存储。
idb
如果您需要完整的 IndexedDB API.
我还建议您考虑在 service worker 的 fetch
处理程序中使用 async
/await
syntax,因为它往往会使基于 promise 的代码更具可读性。
放在一起,大致如下:
self.addEventListener('fetch', (event) => {
event.waitUntil((async () => {
// Your IDB cleanup logic here.
// Basically, anything that can execute separately
// from response generation.
})());
event.respondWith((async () => {
// Your response generation logic here.
// Return a Response object at the end of the function.
})());
});
当应用程序向服务器请求新页面时,我正在尝试在服务工作者的 'fetch' 事件中的 IndexedDB 数据库中做几件事。这就是我的目标:
- 创建一个新的对象存储(它们需要根据'fetch'获取的数据动态创建);
- 在商店中存储一个元素。
或者,如果商店已经存在:
- 从商店获取元素;
- 更新元素并将其存储回商店。
问题是回调(onupgradeneeded、onsuccess 等)永远不会执行。
我一直在尝试使用彼此内部的回调,但我知道这可能不是最好的方法。我也试过在 'fetch' 上放置一个 event.waitUntil()
但它没有帮助。
'fetch'事件,调用函数registerPageAccess
的地方:
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request)
.then(function (response) {
event.waitUntil(function () {
const nextPageURL = new URL(event.request.url);
if (event.request.destination == 'document') {
if (currentURL) {
registerPageAccess(currentURL, nextPageURL);
}
currentURL = nextPageURL;
}
}());
/*
* some other operations
*/
return response || fetch(event.request);
})
);
});
registerPageAccess
,回调函数。
我知道代码很多,但只看第 5 行的 secondRequest.onupgradeneeded
。从来不执行,更不用说后面的了
function registerPageAccess(currentPageURL, nextPageURL) {
var newVersion = parseInt(db.version) + 1;
var secondRequest = indexedDB.open(DB_NAME, newVersion);
secondRequest.onupgradeneeded = function (e) {
db = e.target.result;
db.createObjectStore(currentPageURL, { keyPath: "pageURL" });
var transaction = request.result.transaction([currentPageURL], 'readwrite');
var store = transaction.objectStore(currentPageURL);
var getRequest = store.get(nextPageURL);
getRequest.onsuccess = function (event) {
var obj = getRequest.result;
if (!obj) {
// Insert element into the database
console.debug('ServiceWorker: No matching object in the database');
const addRes = putInObjectStore(nextPageURL, 1, store);
addRes.onsuccess = function (event) {
console.debug('ServiceWorker: Element was successfully added in the Object Store');
}
addRes.onerror = function (event) {
console.error('ServiceWorker error adding element to the Object Store: ' + addRes.error);
}
}
else {
// Updating database element
const updRes = putInObjectStore(obj.pageURL, obj.nVisits + 1, store);
updRes.onsuccess = function (event) {
console.debug('ServiceWorker: Element was successfully updated in the Object Store');
}
updRes.onerror = function (event) {
console.error('ServiceWorker error updating element of the Object Store: ' + putRes.error);
}
}
};
};
secondRequest.onsuccess = function (e) {
console.log('ServiceWorker: secondRequest onsuccess');
};
secondRequest.onerror = function (e) {
console.error('ServiceWorker: error on the secondRequest.open: ' + secondRequest.error);
};
}
我需要一种方法来执行 registerPageAccess
中的操作,其中涉及执行几个回调,但浏览器似乎在它们发生之前就杀死了 Service Worker。
Service Worker 内部的所有异步逻辑都需要基于承诺。因为 IndexedDB 是基于回调的,所以您会发现自己需要将相关的回调包装在 promise 中。
我强烈建议不要尝试自己执行此操作,而是使用以下库之一,这些库经过充分测试、高效且轻量级:
idb-keyval
,如果您不介意简单的键值存储。idb
如果您需要完整的 IndexedDB API.
我还建议您考虑在 service worker 的 fetch
处理程序中使用 async
/await
syntax,因为它往往会使基于 promise 的代码更具可读性。
放在一起,大致如下:
self.addEventListener('fetch', (event) => {
event.waitUntil((async () => {
// Your IDB cleanup logic here.
// Basically, anything that can execute separately
// from response generation.
})());
event.respondWith((async () => {
// Your response generation logic here.
// Return a Response object at the end of the function.
})());
});