fix: close IDB connections when page is frozen (#1196)
OK let's try this
This commit is contained in:
parent
70da9a92a6
commit
43baaf36ae
|
@ -68,7 +68,6 @@
|
||||||
"file-drop-element": "0.2.0",
|
"file-drop-element": "0.2.0",
|
||||||
"form-data": "^2.3.3",
|
"form-data": "^2.3.3",
|
||||||
"glob": "^7.1.3",
|
"glob": "^7.1.3",
|
||||||
"idb-keyval": "^3.2.0",
|
|
||||||
"indexeddb-getall-shim": "^1.3.5",
|
"indexeddb-getall-shim": "^1.3.5",
|
||||||
"intersection-observer": "^0.6.0",
|
"intersection-observer": "^0.6.0",
|
||||||
"localstorage-memory": "^1.0.3",
|
"localstorage-memory": "^1.0.3",
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { DB_VERSION_CURRENT } from './constants'
|
||||||
import { addKnownInstance, deleteKnownInstance } from './knownInstances'
|
import { addKnownInstance, deleteKnownInstance } from './knownInstances'
|
||||||
import { migrations } from './migrations'
|
import { migrations } from './migrations'
|
||||||
import { clearAllCaches } from './cache'
|
import { clearAllCaches } from './cache'
|
||||||
|
import lifecycle from 'page-lifecycle/dist/lifecycle.mjs'
|
||||||
|
|
||||||
const openReqs = {}
|
const openReqs = {}
|
||||||
const databaseCache = {}
|
const databaseCache = {}
|
||||||
|
@ -77,7 +78,6 @@ export function deleteDatabase (instanceName) {
|
||||||
.then(() => clearAllCaches(instanceName))
|
.then(() => clearAllCaches(instanceName))
|
||||||
}
|
}
|
||||||
|
|
||||||
// this should probably only be used in unit tests
|
|
||||||
export function closeDatabase (instanceName) {
|
export function closeDatabase (instanceName) {
|
||||||
// close any open requests
|
// close any open requests
|
||||||
let openReq = openReqs[instanceName]
|
let openReq = openReqs[instanceName]
|
||||||
|
@ -88,3 +88,14 @@ export function closeDatabase (instanceName) {
|
||||||
delete databaseCache[instanceName]
|
delete databaseCache[instanceName]
|
||||||
clearAllCaches(instanceName)
|
clearAllCaches(instanceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process.browser) {
|
||||||
|
lifecycle.addEventListener('statechange', event => {
|
||||||
|
if (event.newState === 'frozen') { // page is frozen, close IDB connections
|
||||||
|
Object.keys(openReqs).forEach(instanceName => {
|
||||||
|
closeDatabase(instanceName)
|
||||||
|
console.log('closed instance DBs')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { set, keys, del } from 'idb-keyval'
|
import { set, keys, del, close } from '../_thirdparty/idb-keyval/idb-keyval'
|
||||||
|
import lifecycle from 'page-lifecycle/dist/lifecycle.mjs'
|
||||||
|
|
||||||
const PREFIX = 'known-instance-'
|
const PREFIX = 'known-instance-'
|
||||||
|
|
||||||
|
@ -15,3 +16,12 @@ export async function addKnownInstance (instanceName) {
|
||||||
export async function deleteKnownInstance (instanceName) {
|
export async function deleteKnownInstance (instanceName) {
|
||||||
return del(PREFIX + instanceName)
|
return del(PREFIX + instanceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process.browser) {
|
||||||
|
lifecycle.addEventListener('statechange', async event => {
|
||||||
|
if (event.newState === 'frozen') { // page is frozen, close IDB connections
|
||||||
|
await close()
|
||||||
|
console.log('closed knownInstances DB')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
Copyright 2016, Jake Archibald
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
|
@ -0,0 +1,98 @@
|
||||||
|
// Forked from https://github.com/jakearchibald/idb-keyval/commit/ea7d507
|
||||||
|
// Adds a function for closing the database, ala https://github.com/jakearchibald/idb-keyval/pull/65
|
||||||
|
class Store {
|
||||||
|
constructor (dbName = 'keyval-store', storeName = 'keyval') {
|
||||||
|
this.storeName = storeName
|
||||||
|
this._dbName = dbName
|
||||||
|
this._storeName = storeName
|
||||||
|
this._init()
|
||||||
|
}
|
||||||
|
|
||||||
|
_withIDBStore (type, callback) {
|
||||||
|
this._init()
|
||||||
|
return this._dbp.then(db => new Promise((resolve, reject) => {
|
||||||
|
const transaction = db.transaction(this.storeName, type)
|
||||||
|
transaction.oncomplete = () => resolve()
|
||||||
|
transaction.onabort = transaction.onerror = () => reject(transaction.error)
|
||||||
|
callback(transaction.objectStore(this.storeName))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
_init () {
|
||||||
|
if (this._dbp) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this._dbp = new Promise((resolve, reject) => {
|
||||||
|
const openreq = indexedDB.open(this._dbName, 1)
|
||||||
|
openreq.onerror = () => reject(openreq.error)
|
||||||
|
openreq.onsuccess = () => resolve(openreq.result)
|
||||||
|
// First time setup: create an empty object store
|
||||||
|
openreq.onupgradeneeded = () => {
|
||||||
|
openreq.result.createObjectStore(this._storeName)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
_close () {
|
||||||
|
this._init()
|
||||||
|
return this._dbp.then(db => {
|
||||||
|
db.close()
|
||||||
|
this._dbp = undefined
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let store
|
||||||
|
|
||||||
|
function getDefaultStore () {
|
||||||
|
if (!store) {
|
||||||
|
store = new Store()
|
||||||
|
}
|
||||||
|
return store
|
||||||
|
}
|
||||||
|
|
||||||
|
function get (key, store = getDefaultStore()) {
|
||||||
|
let req
|
||||||
|
return store._withIDBStore('readonly', store => {
|
||||||
|
req = store.get(key)
|
||||||
|
}).then(() => req.result)
|
||||||
|
}
|
||||||
|
|
||||||
|
function set (key, value, store = getDefaultStore()) {
|
||||||
|
return store._withIDBStore('readwrite', store => {
|
||||||
|
store.put(value, key)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function del (key, store = getDefaultStore()) {
|
||||||
|
return store._withIDBStore('readwrite', store => {
|
||||||
|
store.delete(key)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear (store = getDefaultStore()) {
|
||||||
|
return store._withIDBStore('readwrite', store => {
|
||||||
|
store.clear()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function keys (store = getDefaultStore()) {
|
||||||
|
const keys = []
|
||||||
|
return store._withIDBStore('readonly', store => {
|
||||||
|
// This would be store.getAllKeys(), but it isn't supported by Edge or Safari.
|
||||||
|
// And openKeyCursor isn't supported by Safari.
|
||||||
|
(store.openKeyCursor || store.openCursor).call(store).onsuccess = function () {
|
||||||
|
if (!this.result) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
keys.push(this.result.key)
|
||||||
|
this.result.continue()
|
||||||
|
}
|
||||||
|
}).then(() => keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
function close (store = getDefaultStore()) {
|
||||||
|
return store._close()
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Store, get, set, del, clear, keys, close }
|
Loading…
Reference in New Issue