Access indexed DB in ServiceWorker. Race condition

There are not many examples showing indexedDB in ServiceWorker so far, but the ones I saw were structured as follows:

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 ); } } 

Perhaps this is a crash when starting ServiceWorker, and if so, what is a reliable way to access indexed DB in ServiceWorker?

+8
html5 indexeddb service-worker
source share
3 answers

Opening an IDB every time that starting ServiceWorker is unlikely to be optimal, you will open it even if it will not be used. Instead, open db when you need it. The singleton is very useful here (see https://github.com/jakearchibald/svgomg/blob/master/src/js/utils/storage.js#L5 ), so you do not need to open the IDB twice if it used it twice in own life.

The “activate” event is a great place to open IDB and trigger any “onupdateneeded” events, since the old version of ServiceWorker does not work.

+8
source share

You can wrap a transaction in a promise like this:

 var tx = db.transaction(scope, mode); var p = new Promise(function(resolve, reject) { tx.onabort = function() { reject(tx.error); }; tx.oncomplete = function() { resolve(); }; }); 

Now p will allow / reject when the transaction completes / aborts. This way you can execute arbitrary logic in transaction tx and p.then(...) and / or pass the dependent promise to e.respondWith() or e.waitUntil() , etc.

As other commentators note, we really need to promise IndexedDB. But the composition of his autocommit model after the task and the microtask queues that use Promises make it ... non-trivial for this, without a fundamental API replacement. But (as a developer and one of the specification editors), I am actively prototyping some ideas.

+10
source share

I do not know anything special about accessing IndexedDB from the context of a service worker through access to IndexedDB through a controlled page.

Promises obviously makes your life much easier to maintain, so I found something like, for example, https://gist.github.com/inexorabletash/c8069c042b734519680c to be useful instead of the raw IndexedDB API. But this is not necessary if you create and manage your own promises to reflect the status of IndexedDB asynchronous operations.

The main thing to remember when writing a fetch event handler (and this does not apply to using IndexedDB) is that if you call event.respondWith() , you need to pass either a Response object or a promise that is resolved using the Response object. As long as you do this, it doesn't matter if your Response from IndexedDB or Cache API entries or elsewhere.

Do you encounter any actual problems with the code you posted, or is this more likely a theoretical question?

+4
source share

All Articles