Transform IndexedDB request-like object to a
Promise
.
Promise is a nice way to deal with primitives of IndexedDB. IDBRequest
has onsuccess
and onerror
callbacks, which perfectly map to Promise's resolve
and reject
. The same applies to oncomplete
and onerror
of IDBTransaction
.
If you're going to reuse transactions with Promise
syntax, you can't be sure that it will work in all browsers.
You need to rely on the default callback syntax or use idb-batch.
This issue is well explained in "Tasks, microtasks, queues and schedules" article.
Internally idb-request
fixes IndexedDBShim#204 issue
and allows safely iterate over index cursors.
npm install --save idb-request
Using ES2016 async/await syntax.
import { open } from 'idb-factory'
import { request, requestTransaction, requestCursor } from 'idb-request'
import map from 'lodash.map'
async () => {
const db = await open('mydb', 1, upgradeCallback)
const tr = db.transaction(['books'], 'readwrite')
const books = tr.objectStore('books')
await Promise.all([
request(books.put({ id: 1, title: 'Quarry Memories', author: 'Fred' })),
request(books.put({ id: 2, title: 'Water Buffaloes', author: 'Fred' })),
request(books.put({ id: 3, title: 'Bedrock Nights', author: 'Barney' })),
requestTransaction(tr),
])
const req = books.index('byAuthor').openCursor(null, 'nextunique') // works everywhere
const result = []
await requestCursor(req, (cursor) => {
result.push(cursor.value)
cursor.continue()
})
console.assert(map(result, 'author') === ['Barney', 'Fred'])
}()
function upgradeCallback(e) {
const books = e.target.result.createObjectStore('books', { keyPath: 'id' })
books.createIndex('byTitle', 'title', { unique: true })
books.createIndex('byAuthor', 'author')
}
Each function returns a Promise
.
Listen to request's onsuccess
event.
import { request } from 'idb-request'
const books = db.transaction(['books'], 'readonly').objectStore('books')
request(books.count()).then((count) => {})
Pass the transaction as a second argument to await completion and return the result of the request.
import { request } from 'idb-request'
const tr = db.transaction(['books'], 'readwrite')
const books = tr.objectStore('books')
const req = books.put({ title: 'Store 1' })
request(req, tr).then((requestResult) => {})
Map values over cursor. Iterator has 3 arguments:
cursor
object,result
array, which is returned on resolve. Default value is[]
.stop
resolve promise and exit earlier
import { mapCursor } from 'idb-request'
const limit = 10
const result = await mapCursor(books.openCursor(), (cursor, memo, stop) => {
memo.push(cursor.value)
if (memo.length >= limit) stop()
else cursor.continue()
})
Iterate through object store or index using cursor.
The same example as mapCursor
above:
import { requestCursor } from 'idb-request'
const limit = 10
const result = []
const req = books.openCursor()
await requestCursor(req, (cursor, stop) => {
result.push(cursor.value)
if (memo.length >= limit) stop()
else cursor.continue()
})
// use result array
Listen to transaction's oncomplete
event.
import { request, requestTransaction } from 'idb-request'
const tr = db.transaction(['books'], 'readwrite')
const books = tr.objectStore('books')
await Promise.all([
request(books.put({ id: 1, title: 'Quarry Memories' })),
request(books.put({ id: 2, title: 'Water Buffaloes' })),
request(books.put({ id: 3, title: 'Bedrock Nights' })),
requestTransaction(tr),
])