Skip to content

Dexie.PrematureCommitError

David Fahlander edited this page Nov 1, 2016 · 17 revisions

Inheritance Hierarchy

Since 2.0.0

Description

This exception will be thrown when the indexedDB transaction commits before the promise returned by your transaction scope is resolved or rejected.

Solution:

  1. Make sure to never call other async APIs from within a transaction
  2. Always use the global Promise (or Dexie.Promise) inside transactions.

NOT OK:

db.transaction ('rw', db.friends, () => {
    return fetch(someUrl); // fetch() is a non-indexedDB async API.
});

db.transaction ('rw', db.friends, () => {
    return new Promise (resolve => {
        setTimeout(resolve, 100); // setTimeout is non-indexedDB async API.
    });
});

Dont call setTimeout() or any other async API from inside a transaction.

NOT OK:

let Promise = require('bluebird');
db.transaction('r', db.friends, () => {
    return new Promise((resolve, reject) => {
        db.friends.get(1).then(resolve, reject);
    });
});

Don't use 3-rd part promises within transactions. Must only use Dexie.Promise or the built-in promise (window.Promise / self.Promise / global.Promise) within transactions.

THIS IS OK (in Dexie 2.0.0 and above):

db.transaction('r', db.friends, function () {
    // In Dexie 2.0, it's ok to use the global Promise (Promise.all() in this case)
    return Promise.all([
        db.friends.get(1),
        db.friends.get(2)
    ]);
});

THIS IS ALSO OK:

db.transaction('r', db.friends, async () => {
    // In Dexie 2.0, it's ok to use the global Promise (Promise.all() in this case)
    return await Promise.all([
        db.friends.get(1),
        db.friends.get(2)
    ]);
});

Since Dexie 2.0, you may use the global Promise within transactions, since it will always be temporary patched within the transaction zone. But interactions with non-Dexie API:s must only be done outside transactions. For example if you need to fetch data from a REST API, do that before entering the transaction. And if you need to call REST API based on a database query, do that when your transaction completes.

THIS IS OK:

async function sample() {
    let restData = await fetch(someUrl);
    let dbResult = await db.transaction('rw', db.someTable, async ()=> {
        let changedItems = await db.someTable
            .where('changeDate').above(lastSyncDate)
            .toArray();

        await db.someTable.bulkPut(restData);

        return changedItems;
    });
    await fetch(someUrl, {method: 'POST', body: dbResult});
}

In this trivial sync-sample, the fetch() API is only called from outside the transaction.

Clone this wiki locally