Состояние IndexedDB повреждено .count () после перезапуска браузера - PullRequest
0 голосов
/ 09 апреля 2020

С созданной базой данных, если я выполню .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>
...