-
-
Notifications
You must be signed in to change notification settings - Fork 641
Dexie.waitFor()
Since Dexie 2.0.0-beta.5
Dexie.waitFor(promise, timeout=60000)
This method makes it possible execute asynchronic non-indexedDB work while still keeping current transaction alive. To accomplish this, a separate task will keep the transaction alive by propagating dummy-requests on the transaction while the given promise is being executed. Use this method with caution as it may keep a transaction alive for a long time in case the given promise is late to resolve. Keeping transaction alive means that it will block operations from other transactions while being locked.
This method kind of violate a "holy principle" with IndexedDB. At the same time, it is in line with the new indexeddb-promises proposal where this will be possible. So in a future version if the proposal goes live, Dexie will start ride upon that new API if the browser supports it.
NOTE: indexeddb-promises currently has a slightly different method, waitUntil(), that works almost like this method, except that transaction is committed once the promise completes (as the proposal is today). The reason for naming it differently in Dexie is to distinguish it from the proposal's behavior.
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
await db.transaction('rw', db.friends, async ()=> {
await Dexie.waitFor(sleep(100)); // Sleeps 100 milliseconds
await db.friends.put({id: 1, name: "Åke"});
await Dexie.waitFor(sleep(100)); // Sleeps 100 milliseconds
let theMan = await db.friends.get(1);
alert (`I still got the man: ${theMan.name}`);
});
function sleep (ms) {
return new Promise(function (resolve) { setTimeout(resolve, ms); });
}
db.transaction('rw', db.friends, function () {
Dexie.waitFor(sleep(100)) // Sleeps 100 milliseconds
.then(function (){
return db.friends.put({id: 1, name: "Åke"});
}).then(function () {
return Dexie.waitFor(sleep(100)); // Sleeps 100 milliseconds
}).then(function () {
return db.friends.get(1);
}).then(function (theMan) {
alert ('I still got the man: ' + theMan.name);
});
})
The above samples shows that you can wait for non-IndexedDB Promises to complete while still keeping transaction alive. When Dexie.waitFor()
resolves it is guaranteed that the transaction will be in an active state and possible to continue working on. Note however that while the given promise is being executed, the transaction may not be guaranteed to be in an active state (may temporarily be inactive), so the operation must NOT involve operations on the transaction. But when the waitFor() promise resolves, the transaction is guaranteed to be in active state again.
await db.transaction('rw', db.friends, async ()=> {
await Dexie.waitFor(mixedOperations());
async function mixedOperations () {
await sleep(100);
await db.friends.get(1)
.catch('TransactionInactiveError', ex => {
// This will happen!
});
}
await db.friends.get(1); // Will succeed though.
});
What to keep in mind is this:
- Don't access your own transaction in the operation you wait for using Dexie.waitFor().
- Just access non-IndexedDB work, OR another transaction separate from your own. For example, you MAY start a new top-level transaction or wait on other databases
// We are only locking db.friends initially. But then later in the flow,
// we also lock db.pets to include it as we need it as well.
db.transaction('r', db.friends, () => {
return db.friends.get({name: "Bert"}).then (bert => {
return Dexie.waitFor(db.transaction('r!', db.pets, async () => {
// Locked with exclamation mark ('r!') meaning new top-level transaction.
return db.pets.where({owner: bert.id}).toArray();
})).then(bertsPets => {
bert.pets = bertsPets;
return bert;
});
}).then(bertWithPets => {
// bertWithPets is now a "friend" with a 'pets' property added to it, that
// is an array of the pets that is owned by Bert.
});
});
Dexie.js - minimalistic and bullet proof indexedDB library