在ServiceWorker中还没有很多示例证明indexedDB,但我看到的结构都是这样的:
const request = indexedDB.open( 'myDB', 1 );
var db;
request.onupgradeneeded = ...
request.onsuccess = function() {
db = this.result; // Average 8ms
};
self.onfetch = function(e)
{
const requestURL = new URL( e.request.url ),
path = requestURL.pathname;
if( path === '/test' )
{
const response = new Promise( function( resolve )
{
console.log( performance.now(), typeof db ); // Average 15ms
db.transaction( 'cache' ).objectStore( 'cache' ).get( 'test' ).onsuccess = function()
{
resolve( new Response( this.result, { headers: { 'content-type':'text/plain' } } ) );
}
});
e.respondWith( response );
}
}
ServiceWorker启动时可能会失败,如果是这样,在ServiceWorker中访问indexedDB的有效方法是什么?
答案 0 :(得分:11)
您可以将事务包装在这样的承诺中:
var tx = db.transaction(scope, mode);
var p = new Promise(function(resolve, reject) {
tx.onabort = function() { reject(tx.error); };
tx.oncomplete = function() { resolve(); };
});
现在p
将在事务完成/中止时解析/拒绝。因此,您可以在tx
交易和p.then(...)
中执行任意逻辑和/或将相关承诺传递到e.respondWith()
或e.waitUntil()
等。
正如其他评论者所指出的,我们确实需要宣传IndexedDB。但是它的任务后自动提交模型的组成和Promises使用的微任务队列使得...在没有基本上完全替换API的情况下这样做是非常重要的。但是(作为实施者和规范编辑之一)我正在积极地为一些想法做原型。
答案 1 :(得分:8)
每次ServiceWorker启动时打开IDB都不太可能是最佳的,即使没有使用它也会打开它。而是在需要时打开数据库。单身人士在这里非常有用(参见https://github.com/jakearchibald/svgomg/blob/master/src/js/utils/storage.js#L5),因此如果在生命周期内使用过两次,你就不需要再开两次。
"激活"活动是开放IDB的好地方,让任何" onupdateneeded"事件运行,因为旧版本的ServiceWorker已经不在了。
答案 2 :(得分:4)
我不知道通过受控页面访问IndexedDB从服务工作者的上下文访问IndexedDB有什么特别之处。
Promise显然会让服务工作者的生活变得更轻松,所以我发现使用像https://gist.github.com/inexorabletash/c8069c042b734519680c这样的东西来代替原始的IndexedDB API。但只要您创建和管理自己的promise以反映异步IndexedDB操作的状态,它就不是强制性的。
编写fetch
事件处理程序时要记住的主要事项(这不是特定于使用IndexedDB),如果您调用event.respondWith()
,则需要传入Response
对象或使用Response
对象解析的promise。只要你这样做,你的Response
是从IndexedDB条目还是Cache API或其他地方构建的都无关紧要。
您是否遇到了所发布代码的任何实际问题,或者这更像是一个理论问题?