From 64e3424a3cbe0b7c4e2930ee563e9950dcff1593 Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Tue, 19 Mar 2024 22:12:14 -0700 Subject: [PATCH] fix: try not pooling indexeddb --- src/database/Database.js | 6 ++-- src/database/databaseLifecycle.js | 57 +++++++++++-------------------- 2 files changed, 23 insertions(+), 40 deletions(-) diff --git a/src/database/Database.js b/src/database/Database.js index 2889f78..3efb844 100644 --- a/src/database/Database.js +++ b/src/database/Database.js @@ -10,7 +10,7 @@ import { uniqEmoji } from './utils/uniqEmoji' import { closeDatabase, deleteDatabase, - addOnCloseListener, + setOnCloseListener, openDatabase } from './databaseLifecycle' import { @@ -38,7 +38,7 @@ export default class Database { async _init () { const db = this._db = await openDatabase(this._dbName) - addOnCloseListener(this._dbName, this._clear) + setOnCloseListener(db, this._clear) const dataSource = this.dataSource const empty = await isEmpty(db) @@ -152,7 +152,7 @@ export default class Database { async close () { await this._shutdown() - await closeDatabase(this._dbName) + await closeDatabase(this._db) } async delete () { diff --git a/src/database/databaseLifecycle.js b/src/database/databaseLifecycle.js index 9049b4b..897ddca 100644 --- a/src/database/databaseLifecycle.js +++ b/src/database/databaseLifecycle.js @@ -1,9 +1,8 @@ import { initialMigration } from './migrations' import { DB_VERSION_INITIAL, DB_VERSION_CURRENT } from './constants' -export const openIndexedDBRequests = {} -const databaseCache = {} -const onCloseListeners = {} +export const openIndexedDBs = [] +const onCloseListeners = new WeakMap() function handleOpenOrDeleteReq (resolve, reject, req) { // These things are almost impossible to test with fakeIndexedDB sadly @@ -14,11 +13,11 @@ function handleOpenOrDeleteReq (resolve, reject, req) { req.onsuccess = () => resolve(req.result) } -async function createDatabase (dbName) { - performance.mark('createDatabase') +export async function openDatabase (dbName) { + performance.mark('openDatabase') const db = await new Promise((resolve, reject) => { const req = indexedDB.open(dbName, DB_VERSION_CURRENT) - openIndexedDBRequests[dbName] = req + req.onupgradeneeded = e => { // Technically there is only one version, so we don't need this `if` check // But if an old version of the JS is in another browser tab @@ -31,23 +30,19 @@ async function createDatabase (dbName) { } handleOpenOrDeleteReq(resolve, reject, req) }) + if (import.meta.env.MODE === 'test') { + openIndexedDBs.push(db) + } // Handle abnormal closes, e.g. "delete database" in chrome dev tools. // No need for removeEventListener, because once the DB can no longer // fire "close" events, it will auto-GC. // Unfortunately cannot test in fakeIndexedDB: https://github.com/dumbmatter/fakeIndexedDB/issues/50 /* istanbul ignore next */ db.onclose = () => closeDatabase(dbName) - performance.measure('createDatabase', 'createDatabase') + performance.measure('openDatabase', 'openDatabase') return db } -export function openDatabase (dbName) { - if (!databaseCache[dbName]) { - databaseCache[dbName] = createDatabase(dbName) - } - return databaseCache[dbName] -} - export function dbPromise (db, storeName, readOnlyOrReadWrite, cb) { return new Promise((resolve, reject) => { // Use relaxed durability because neither the emoji data nor the favorites/preferred skin tone @@ -67,29 +62,21 @@ export function dbPromise (db, storeName, readOnlyOrReadWrite, cb) { }) } -export function closeDatabase (dbName) { - // close any open requests - const req = openIndexedDBRequests[dbName] - const db = req && req.result - if (db) { - db.close() - const listeners = onCloseListeners[dbName] - /* istanbul ignore else */ - if (listeners) { - for (const listener of listeners) { - listener() - } - } +export function closeDatabase (db) { + db.close() + const listener = onCloseListeners.get(db) + if (listener) { + listener() + } + onCloseListeners.delete(db) + if (import.meta.env.MODE === 'test') { + openIndexedDBs.splice(openIndexedDBs.indexOf(db), 1) } - delete openIndexedDBRequests[dbName] - delete databaseCache[dbName] - delete onCloseListeners[dbName] } export function deleteDatabase (dbName) { return new Promise((resolve, reject) => { // close any open requests - closeDatabase(dbName) const req = indexedDB.deleteDatabase(dbName) handleOpenOrDeleteReq(resolve, reject, req) }) @@ -98,10 +85,6 @@ export function deleteDatabase (dbName) { // The "close" event occurs during an abnormal shutdown, e.g. a user clearing their browser data. // However, it doesn't occur with the normal "close" event, so we handle that separately. // https://www.w3.org/TR/IndexedDB/#close-a-database-connection -export function addOnCloseListener (dbName, listener) { - let listeners = onCloseListeners[dbName] - if (!listeners) { - listeners = onCloseListeners[dbName] = [] - } - listeners.push(listener) +export function setOnCloseListener (db, listener) { + onCloseListeners.set(db, listener) }