@@ -11,6 +11,7 @@ inline constexpr std::string_view indexeddb_compatibility_source = R"JS(
1111 if (typeof nativeStorage !== 'function') return;
1212 const openConnections = new Map();
1313 const loadedDatabases = new Map();
14+ const writeTails = new Map();
1415 const clone = value => structuredClone(value);
1516 const failure = (message, name) => new DOMException(message, name);
1617 const event = (type, fields = {}) => Object.assign({
@@ -233,6 +234,7 @@ R"JS( class IDBTransaction extends EventTarget {
233234 this._active = true;
234235 this._pending = 0;
235236 this._finishScheduled = false;
237+ this._commitQueued = false;
236238 this._mutations = [];
237239 this._settled = versionchange ? new Promise((resolve, reject) => {
238240 this._settleResolve = resolve;
@@ -289,7 +291,23 @@ R"JS( class IDBTransaction extends EventTarget {
289291 else this._commit();
290292 }, 0);
291293 }
292- async _commit(attempt = 0) {
294+ async _commit() {
295+ if (this._commitQueued) return;
296+ this._commitQueued = true;
297+ const name = this.db.name;
298+ const previous = writeTails.get(name) ?? Promise.resolve();
299+ let release;
300+ const current = new Promise(resolve => { release = resolve; });
301+ writeTails.set(name, current);
302+ await previous.catch(() => {});
303+ try {
304+ if (this._active) await this._commitNow();
305+ } finally {
306+ release();
307+ if (writeTails.get(name) === current) writeTails.delete(name);
308+ }
309+ }
310+ async _commitNow(attempt = 0) {
293311 try {
294312 const revision = await nativeStorage(
295313 'store', this.db.name, this._revision, this._state);
@@ -321,7 +339,7 @@ R"JS( class IDBTransaction extends EventTarget {
321339 }
322340 this._state = state;
323341 this._revision = latest.revision;
324- return this._commit (attempt + 1);
342+ return this._commitNow (attempt + 1);
325343 } catch (reloadError) { error = reloadError; }
326344 }
327345 this._fail(error);
0 commit comments