fix: close IDB connections when page is frozen (#1196)

OK let's try this
This commit is contained in:
Nolan Lawson 2019-05-08 20:53:33 -07:00 committed by GitHub
parent 70da9a92a6
commit 43baaf36ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 134 additions and 3 deletions

View file

@ -68,7 +68,6 @@
"file-drop-element": "0.2.0",
"form-data": "^2.3.3",
"glob": "^7.1.3",
"idb-keyval": "^3.2.0",
"indexeddb-getall-shim": "^1.3.5",
"intersection-observer": "^0.6.0",
"localstorage-memory": "^1.0.3",

View file

@ -2,6 +2,7 @@ import { DB_VERSION_CURRENT } from './constants'
import { addKnownInstance, deleteKnownInstance } from './knownInstances'
import { migrations } from './migrations'
import { clearAllCaches } from './cache'
import lifecycle from 'page-lifecycle/dist/lifecycle.mjs'
const openReqs = {}
const databaseCache = {}
@ -77,7 +78,6 @@ export function deleteDatabase (instanceName) {
.then(() => clearAllCaches(instanceName))
}
// this should probably only be used in unit tests
export function closeDatabase (instanceName) {
// close any open requests
let openReq = openReqs[instanceName]
@ -88,3 +88,14 @@ export function closeDatabase (instanceName) {
delete databaseCache[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')
})
}
})
}

View file

@ -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-'
@ -15,3 +16,12 @@ export async function addKnownInstance (instanceName) {
export async function deleteKnownInstance (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')
}
})
}

View file

@ -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.

View file

@ -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 }