С созданной базой данных, если я выполню .count()
в хранилище объектов или индекс после перезапуска Safari (Safari 13.1), он каким-то образом блокирует базу данных и завершается ошибкой при следующей операции «readwrite», этого не происходит в Chrome.
В приведенном ниже примере кода после загрузки страницы создается база данных, выполняется счетчик (он работает правильно), и вы можете добавлять элементы в хранилище объектов. Если вы закроете браузер и откроете его снова, счетчик будет выполнен, но вы больше не сможете вставлять больше элементов. Транзакции прерываются.
Если .count()
выполняется через несколько секунд, а не только в обработчике успеха (например, через 5 секунд после загрузки страницы), он не блокируется. база данных и все работает. Другой альтернативой, которая работает, является выполнение .getAll()
и получение .length
результата, и это работает, что означает, что база данных доступна.
Что происходит? Что я могу сделать, чтобы позвонить .count()
только в начале?
<!DOCTYPE html>
<html>
<head>
<title>Bug indexes corrupted by count() after restart</title>
</head>
<body>
<button id="clear-btn">Clear</button>
<button id="insert-not-working">Insert should not work after restarting Safari</button>
<script>
document.getElementById('clear-btn').addEventListener('click', () => {
db.close();
indexedDB.deleteDatabase('bug');
console.log('Database deleted, reload the page to start again');
});
document.getElementById('insert-not-working').addEventListener('click', async () => {
console.log('trying to insert');
const obj1 = await store({created: new Date()}).catch(console.error);
console.log('Object stored', obj1);
console.log('Object inserted, should see an error if you have relaunched Safari');
});
let db, created = false;
const dbrequest = indexedDB.open('bug');
dbrequest.addEventListener('error', console.error);
dbrequest.addEventListener('blocked', console.error);
dbrequest.addEventListener('upgradeneeded', (e) => {
const db = e.target.result;
const objs = db.createObjectStore('objectstore', {keyPath: 'id', autoIncrement: true});
console.log('Database did not exist, we just created it');
});
dbrequest.addEventListener('success', (e) => {
db = e.target.result;
db.addEventListener('error', console.error);
db.addEventListener('abort', console.error);
db.addEventListener('versionchange', console.log);
db.addEventListener('close', console.error);
console.log('Database exists, now you can insert the objects');
// This doesn't work
count().then(n => console.log('This is the problematic count', n));
// It does work if we call the count later
// setTimeout(() => count().then(n => console.log('This is not a problematic count', n)), 5000);
});
function count() {
return new Promise((resolve, reject) => {
const objectStore = db.transaction('objectstore', 'readonly').objectStore('objectstore');
const request = objectStore.count();
request.addEventListener('success', (e) => resolve(e.target.result));
// It works if instead we did with getAll().length
// const request = objectStore.getAll();
// request.addEventListener('success', (e) => resolve(e.target.result.length));
request.addEventListener('error', reject);
});
}
function store(obj) {
return new Promise((resolve, reject) => {
const transaction = db.transaction('objectstore', 'readwrite');
const objectStore = transaction.objectStore('objectstore');
const request = objectStore.put(obj);
request.addEventListener('success', (e) => obj.id = e.target.result);
transaction.addEventListener('complete', () => resolve(obj));
transaction.addEventListener('abort', (e) => {
e.stopPropagation();
console.error(`Error storing ${JSON.stringify(obj)}`, e);
reject(e);
});
request.addEventListener('error', reject);
});
}
</script>
</body>
</html>