Refactor IndexedDB
This commit is contained in:
2 files changed
+92
-77
No files matched your search
+11
-77
@@ -1,90 +1,23 @@
|
||||
import largeAssets from './large-assets';
|
||||
import {buildId} from './lib/build-id';
|
||||
import Database from './lib/idb';
|
||||
|
||||
// We can't trust the HTTP cache to reliably cache these large assets
|
||||
|
||||
const DATABASE_NAME = 'p4-large-assets';
|
||||
const DATABASE_VERSION = 1;
|
||||
|
||||
const STORE_NAME = 'assets';
|
||||
|
||||
let _db;
|
||||
const db = new Database(DATABASE_NAME, DATABASE_VERSION, STORE_NAME);
|
||||
|
||||
const getAssetId = (asset) => {
|
||||
return `${asset.src}-${asset.type}-${asset.sha256 || buildId}`;
|
||||
};
|
||||
|
||||
// https://github.com/jakearchibald/safari-14-idb-fix/blob/582bbdc7230891113bfb5743391550cbf29d21f2/src/index.ts
|
||||
const idbReady = () => {
|
||||
const isSafari =
|
||||
!navigator.userAgentData &&
|
||||
/Safari\//.test(navigator.userAgent) &&
|
||||
!/Chrom(e|ium)\//.test(navigator.userAgent);
|
||||
|
||||
// No point putting other browsers or older versions of Safari through this mess.
|
||||
if (!isSafari || !indexedDB.databases) return Promise.resolve();
|
||||
|
||||
let intervalId;
|
||||
return new Promise((resolve) => {
|
||||
const tryIdb = () => indexedDB.databases().finally(resolve);
|
||||
intervalId = setInterval(tryIdb, 100);
|
||||
tryIdb();
|
||||
}).finally(() => clearInterval(intervalId));
|
||||
};
|
||||
|
||||
const openDB = async () => {
|
||||
if (_db) {
|
||||
return _db;
|
||||
}
|
||||
if (!window.indexedDB) {
|
||||
throw new Error('indexedDB is not supported');
|
||||
}
|
||||
await idbReady();
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open(DATABASE_NAME, DATABASE_VERSION);
|
||||
request.onupgradeneeded = e => {
|
||||
const db = e.target.result;
|
||||
db.createObjectStore(STORE_NAME, {
|
||||
keyPath: 'id'
|
||||
});
|
||||
};
|
||||
request.onsuccess = (e) => {
|
||||
_db = e.target.result;
|
||||
removeExtraneous()
|
||||
.then(() => {
|
||||
resolve(_db);
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
};
|
||||
request.onerror = (e) => {
|
||||
reject(new Error(`IDB Error ${e.target.error}`));
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const createTransaction = async (readwrite) => {
|
||||
const db = await openDB();
|
||||
const transaction = db.transaction(STORE_NAME, readwrite);
|
||||
const store = transaction.objectStore(STORE_NAME);
|
||||
return {
|
||||
db,
|
||||
transaction,
|
||||
store
|
||||
};
|
||||
};
|
||||
|
||||
const setTransactionErrorHandler = (transaction, reject) => {
|
||||
transaction.onerror = () => {
|
||||
reject(new Error(`Transaction error: ${transaction.error}`))
|
||||
};
|
||||
};
|
||||
|
||||
const removeExtraneous = async () => {
|
||||
const {transaction, store} = await createTransaction('readwrite');
|
||||
const {transaction, store} = await db.createTransaction('readwrite');
|
||||
return new Promise((resolve, reject) => {
|
||||
setTransactionErrorHandler(transaction, reject);
|
||||
Database.setTransactionErrorHandler(transaction, reject);
|
||||
const allValidAssetIds = Object.values(largeAssets).map(getAssetId);
|
||||
const request = store.openCursor();
|
||||
request.onsuccess = e => {
|
||||
@@ -101,11 +34,12 @@ const removeExtraneous = async () => {
|
||||
};
|
||||
});
|
||||
};
|
||||
db.onopen = removeExtraneous;
|
||||
|
||||
const get = async (asset) => {
|
||||
const {transaction, store} = await createTransaction('readonly');
|
||||
const {transaction, store} = await db.createTransaction('readonly');
|
||||
return new Promise((resolve, reject) => {
|
||||
setTransactionErrorHandler(transaction, reject);
|
||||
Database.setTransactionErrorHandler(transaction, reject);
|
||||
const assetId = getAssetId(asset);
|
||||
const request = store.get(assetId);
|
||||
request.onsuccess = (e) => {
|
||||
@@ -120,9 +54,9 @@ const get = async (asset) => {
|
||||
};
|
||||
|
||||
const set = async (asset, content) => {
|
||||
const {transaction, store} = await createTransaction('readwrite');
|
||||
const {transaction, store} = await db.createTransaction('readwrite');
|
||||
return new Promise((resolve, reject) => {
|
||||
setTransactionErrorHandler(transaction, reject);
|
||||
Database.setTransactionErrorHandler(transaction, reject);
|
||||
const assetId = getAssetId(asset);
|
||||
const request = store.put({
|
||||
id: assetId,
|
||||
@@ -135,9 +69,9 @@ const set = async (asset, content) => {
|
||||
};
|
||||
|
||||
const resetAll = async () => {
|
||||
const {transaction, store} = await createTransaction('readwrite');
|
||||
const {transaction, store} = await db.createTransaction('readwrite');
|
||||
return new Promise((resolve, reject) => {
|
||||
setTransactionErrorHandler(transaction, reject);
|
||||
Database.setTransactionErrorHandler(transaction, reject);
|
||||
const request = store.openCursor();
|
||||
request.onsuccess = e => {
|
||||
const cursor = e.target.result;
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
// https://github.com/jakearchibald/safari-14-idb-fix/blob/582bbdc7230891113bfb5743391550cbf29d21f2/src/index.ts
|
||||
const idbReady = () => {
|
||||
const isSafari =
|
||||
!navigator.userAgentData &&
|
||||
/Safari\//.test(navigator.userAgent) &&
|
||||
!/Chrom(e|ium)\//.test(navigator.userAgent);
|
||||
|
||||
// No point putting other browsers or older versions of Safari through this mess.
|
||||
if (!isSafari || !indexedDB.databases) return Promise.resolve();
|
||||
|
||||
let intervalId;
|
||||
return new Promise((resolve) => {
|
||||
const tryIdb = () => indexedDB.databases().finally(resolve);
|
||||
intervalId = setInterval(tryIdb, 100);
|
||||
tryIdb();
|
||||
}).finally(() => clearInterval(intervalId));
|
||||
};
|
||||
|
||||
class Database {
|
||||
constructor (name, version, storeName) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
this.storeName = storeName;
|
||||
this.db = null;
|
||||
}
|
||||
|
||||
async open () {
|
||||
if (this.db) {
|
||||
return this.db;
|
||||
}
|
||||
if (!window.indexedDB) {
|
||||
throw new Error('indexedDB is not supported');
|
||||
}
|
||||
await idbReady();
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open(this.name, this.version);
|
||||
request.onupgradeneeded = (e) => {
|
||||
const db = e.target.result;
|
||||
db.createObjectStore(this.storeName, {
|
||||
keyPath: 'id'
|
||||
});
|
||||
};
|
||||
request.onsuccess = (e) => {
|
||||
this.db = e.target.result;
|
||||
this.onopen()
|
||||
.then(() => {
|
||||
resolve(this.db);
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
};
|
||||
request.onerror = (e) => {
|
||||
reject(new Error(`IDB Error ${e.target.error}`));
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async createTransaction (readwrite) {
|
||||
const db = await this.open();
|
||||
const transaction = db.transaction(this.storeName, readwrite);
|
||||
const store = transaction.objectStore(this.storeName);
|
||||
return {
|
||||
db,
|
||||
transaction,
|
||||
store
|
||||
};
|
||||
}
|
||||
|
||||
onopen () {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
Database.setTransactionErrorHandler = (transaction, reject) => {
|
||||
transaction.onerror = () => {
|
||||
reject(new Error(`Transaction error: ${transaction.error}`))
|
||||
};
|
||||
};
|
||||
|
||||
export default Database;
|
||||
Reference in new issue
Block a user