jakearchibald / idb-keyval

A super-simple-small promise-based keyval store implemented with IndexedDB

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Safari iOS/iPadOS 14.6 Bug: First Attempt at Opening indexedDB gets Stuck

ecrookoh opened this issue · comments

I have run into an issue with the new Safari update for iOS/iPadOS 14.6 and idb-keyval.
It may also affect Safari 14.1.1 on macOS 11.4, but I have not tested that myself.

The first attempt to access the indexedDB of Safari fails, and no further code is run in my app. Refreshing the page does allow the website to load, as is mentioned in the bug report linked below.

Workaround described below is a race condition.
I was able to use the workaround suggested in the links below by adding const db = window.indexedDB.open("test"); to the index.js of my app before anything else is called.

Webkit Bug Report: https://bugs.webkit.org/show_bug.cgi?id=226547
Apple Developer Forum: https://developer.apple.com/forums/thread/681201

I'm not sure if it makes sense to integrate the current workaround into the idb-keyval code. There is a developer assigned to the bug on the Webkit bug report, so this will hopefully be fixed in the next update to iOS.
However, I will probably keep the workaround in my code to maintain compatibility for people who don't update from iOS 14.6.

I'm trying to get more details on this. If second-connection always works, I'll add it in. I'm not sure what to do if the second connection is still a race.

Thanks for taking a look at this

The workarounds I've seen recommended do seem to either use a timeout or suggest putting the initial attempt at accessing the indexedDB as early as possible in your code. Both options seem likely to be working around a race condition, unless anyone official can confirm differently.

Here's a little library that works around this bug https://www.npmjs.com/package/safari-14-idb-fix.

I'll probably integrate it into idb-keyval.

I tried the safari-14-idb-fix (thx a lot for this) but, in my Ionic app, it did not solve the issue when the app runs in wkwebwebview (capacitor). Tried multiple times, no luck. Fortunately OP's workaround (window.indexedDB.open("test");) did work out.

commented

Here's a little library that works around this bug https://www.npmjs.com/package/safari-14-idb-fix.

I'll probably integrate it into idb-keyval.

Does this fix the issue 100% I've tried the OP's fix and it made it happen less frequent, but I've found if you move between pages very quickly in the app, or resume from background after a period of inactivity and then navigate to a different page IndexedDB gets locked up (DB shows in the Storage tab but is empty).

commented

I've also raised a bug report about the issue for iOS 15 so hopefully this will get some attention. If anyone has a contained project with this occurring and how to reproduce it would be handy.

The fix in the OP is not a fix, it's still a race condition. https://www.npmjs.com/package/safari-14-idb-fix is a proper fix.

@BRadHoc the bug has already been fixed, it just takes ages for Safari fixes to reach users https://bugs.webkit.org/show_bug.cgi?id=226547

commented

@jakearchibald it's still happening on iOS 15 beta 2 so I'd expect it to be present in iOS 14.7 at least. If you've got a way of implementing the fix into idbKeyval that'd be ideal as currently I'd have to go through and do everything individually as wrapping everything in an idbReady messes with globals

Yeah, fair enough. In the meantime, you might find it easy to create your own module like this:

import idbReady from 'safari-14-idb-fix';
import * as idbKeyval from 'idb-keyval';

const ready = idbReady();
export const get = (...args) => ready.then(() => idbKeyval.get(...args));
export const set = (...args) => ready.then(() => idbKeyval.set(...args));
// etc etc
commented

Yeah, fair enough. In the meantime, you might find it easy to create your own module like this:

import idbReady from 'safari-14-idb-fix';
import * as idbKeyval from 'idb-keyval';

const ready = idbReady();
export const get = (...args) => ready.then(() => idbKeyval.get(...args));
export const set = (...args) => ready.then(() => idbKeyval.set(...args));
// etc etc

So I got this set up, now what seems to happen is, when the app is launched, the ready never fires, until you do a refresh, then it executes successfully.

To workaround I'm checking for the execution of the promise and falling back to reloading the page.


let promise_check = false;
storeGet("userid").then(async function(get_userid) {
      promise_check = true;
      //code to execute onReady
}).catch(function(e) {
     console.error("There was an issue initialising IndexedDB");
     location.reload();
});

let check_promise = setTimeout(() => { if (!promise_check) { location.reload(); } }, 500);

Can you give me steps to recreate the problem locally?

commented

Create a new Cordova project for iOS, have an index page that does a bunch of stuff with IDB and then depending on the outcome navigates to another page that also does some stuff onload with IDB (with the fix applied) (without the promise_check).

If that doesn't recreate it (but I think it should) I'll try and make a project with it.

commented

Hello guys, any news on this topic ?

See https://bugs.webkit.org/show_bug.cgi?id=226547#c50, Apple has shipped the fix in iOS 14.7.

Fixed in 033cd8d, published as 5.1.0.

It's no longer necessery to use the fix in #120 (comment), but it won't cause a problem if you do.

Apple has shipped the fix in iOS 14.7

Yeah, but it might be a long time before all users pick up the change.

Thanks for fixing this and documenting it! Really appreciate it.