Reputation: 9257
I have a function that is used to add a record to the IndexDb database:
async function addAsync(storeName, object) {
return new Promise((res, rej) => {
// openDatabaseAsync() is another reusable method to open the db. That works fine.
openDatabaseAsync().then(db => {
var store = openObjectStore(db, storeName, 'readwrite');
var addResult = store.add(JSON.parse(object));
addResult.onsuccess = res;
addResult.onerror = (e) => {
console.log("addResult Error");
throw e;
};
}).catch(e => {
// Error from "throw e;" above NOT GETTING CAUGHT HERE!
console.error("addAsync ERROR > ", e, storeName, object);
rej(e);
});
})
}
If I try to add a duplicate key, then I expect:
addResult.onerror = (e) => {
console.log("addResult Error");
throw e;
}
to capture that. It does.
But then, I also expect my
.catch(e => {
// Error from "throw e;" above NOT GETTING CAUGHT HERE!
console.error("addAsync ERROR > ", e, storeName, object);
rej(e);
})
to catch that error. But instead I get an "uncaught" log.
Console output:
addResult Error
Uncaught Event {isTrusted: true, type: "error", target: IDBRequest, currentTarget: IDBRequest, eventPhase: 2, …}
Does that final .catch only handle exceptions from the openDatabaseAsync call? I would have thought now as it is chained to the .then.
In summary, here's what I would expect from the above code:
However, I would have thought that I should get the log from the line:
console.error("addAsync ERROR > ", e, storeName, object);
before the reject is sent back to the caller of addAsync(), which may be unhandled at that point.
Upvotes: 1
Views: 365
Reputation: 338416
Your approach would benefit form a larger overhaul.
async
when it's not also using await
.new Promise()
for an operation that returns a promise, such as openDatabaseAsync()
does. Return that promise, or switch to async/await
.On the example of IDBRequest
:
function promisifyIDBRequest(idbr) {
return new Promise( (resolve, reject) => {
idbr.onsuccess = () => resolve(idbr.result);
idbr.onerror = (e) => reject(e.target.error);
});
}
Now you can do this:
async function addAsync(storeName, object) {
const db = await openDatabaseAsync();
const store = openObjectStore(db, storeName, 'readwrite');
return promisifyIDBRequest(store.add(JSON.parse(object)));
}
Add a try/catch block if you want to handle errors inside of addAsync()
.
It's worth checking out existing solutions that wrap the entire IndexedDB interface with promise semantics, such as https://github.com/jakearchibald/idb.
FWIW, the promise-chain variant of the above function would look like this:
function addAsync(storeName, object) {
return openDatabaseAsync().then( (db) => {
const store = openObjectStore(db, storeName, 'readwrite');
return promisifyIDBRequest(store.add(JSON.parse(object)));
});
}
both variants return a promise for an IDBRequest result.
Upvotes: 3