(failed) attempt at a repro case for the safari TransactionInactiveError
This commit is contained in:
parent
f402e8c6c4
commit
b08b7e521a
1 changed files with 169 additions and 0 deletions
169
prototypes/idb-promises-safari.html
Normal file
169
prototypes/idb-promises-safari.html
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function reqAsPromise(req) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
req.onsuccess = function() {
|
||||||
|
resolve(req.result);
|
||||||
|
};
|
||||||
|
req.onerror = function(e) {
|
||||||
|
reject(new Error("IDB request failed: " + req.error));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function txnAsPromise(txn) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
txn.oncomplete = function() {
|
||||||
|
resolve(txn);
|
||||||
|
};
|
||||||
|
txn.onabort = function(e) {
|
||||||
|
reject(new Error("Transaction got aborted: " + txn.error));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const BrowserMutationObserver = window.MutationObserver || window.WebKitMutationObserver;
|
||||||
|
|
||||||
|
function useMutationObserver(flush) {
|
||||||
|
let iterations = 0;
|
||||||
|
const observer = new BrowserMutationObserver(flush);
|
||||||
|
const node = document.createTextNode('');
|
||||||
|
observer.observe(node, { characterData: true });
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
node.data = (iterations = ++iterations % 2);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const wait = (function() {
|
||||||
|
let resolve = null;
|
||||||
|
const trigger = useMutationObserver(() => {
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
return new Promise(r => {
|
||||||
|
resolve = r;
|
||||||
|
trigger();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
var _resolve = Promise.resolve.bind(Promise);
|
||||||
|
var _then = Promise.prototype.then;
|
||||||
|
|
||||||
|
async function delay() {
|
||||||
|
return Promise.resolve();
|
||||||
|
// two consecutive macro tasks
|
||||||
|
//await new Promise(r => setImmediate(r));
|
||||||
|
// the next macro task will now be the complete event of the txn,
|
||||||
|
// so schedule another macro task to execute after that
|
||||||
|
//await new Promise(r => setImmediate(r));
|
||||||
|
//return;
|
||||||
|
// for (let i = 0; i < 1000; i+=1) {
|
||||||
|
// console.log("await...");
|
||||||
|
// await wait();
|
||||||
|
// }
|
||||||
|
let p = _resolve(0);
|
||||||
|
for (let i=0;i<10;++i) {
|
||||||
|
p = _then.call(p, x => x + 1);
|
||||||
|
}
|
||||||
|
let result = await p;
|
||||||
|
console.log("Result: "+ result + " (should be 10)");
|
||||||
|
}
|
||||||
|
|
||||||
|
class Storage {
|
||||||
|
constructor(databaseName) {
|
||||||
|
this._databaseName = databaseName;
|
||||||
|
this._database = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
open() {
|
||||||
|
const req = window.indexedDB.open(this._databaseName);
|
||||||
|
const self = this;
|
||||||
|
req.onupgradeneeded = function(ev) {
|
||||||
|
const db = ev.target.result;
|
||||||
|
const oldVersion = ev.oldVersion;
|
||||||
|
self._createStores(db, oldVersion);
|
||||||
|
};
|
||||||
|
return reqAsPromise(req).then(function() {
|
||||||
|
self._database = req.result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openTxn(mode, storeName) {
|
||||||
|
const txn = this._database.transaction([storeName], mode);
|
||||||
|
txn.addEventListener("complete", () => {
|
||||||
|
console.info(`transaction ${mode} for ${storeName} completed`);
|
||||||
|
});
|
||||||
|
txn.addEventListener("abort", e => {
|
||||||
|
console.warn(`transaction ${mode} for ${storeName} aborted`, e.target.error);
|
||||||
|
});
|
||||||
|
return txn;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createStores(db) {
|
||||||
|
db.createObjectStore("foos", {keyPath: "id"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAll(store, depth = 0) {
|
||||||
|
if (depth < 15) {
|
||||||
|
return await getAll(store, depth + 1);
|
||||||
|
}
|
||||||
|
const request = store.openCursor();
|
||||||
|
const results = [];
|
||||||
|
return await new Promise(function(resolve, reject) {
|
||||||
|
request.onsuccess = function(event) {
|
||||||
|
const cursor = event.target.result;
|
||||||
|
if(cursor) {
|
||||||
|
results.push(cursor.value);
|
||||||
|
cursor.continue();
|
||||||
|
} else {
|
||||||
|
resolve(results);
|
||||||
|
Promise.flushQueue && Promise.flushQueue();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
request.onerror = function(e) {
|
||||||
|
reject(new Error("IDB request failed: " + e.target.error.message));
|
||||||
|
Promise.flushQueue && Promise.flushQueue();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
try {
|
||||||
|
let storage = new Storage("idb-promises");
|
||||||
|
await storage.open();
|
||||||
|
//await reqAsPromise(storage.openTxn("readwrite", "foos").objectStore("foos").clear());
|
||||||
|
|
||||||
|
for (let i = 0; i < 10; i += 1) {
|
||||||
|
storage.openTxn("readonly", "foos").objectStore("foos").get(5);
|
||||||
|
//console.log("from readtxn", await reqAsPromise(storage.openTxn("readonly", "foos").objectStore("foos").get(5)));
|
||||||
|
const txn = storage.openTxn("readwrite", "foos");
|
||||||
|
const store = txn.objectStore("foos");
|
||||||
|
console.log("writing the foos");
|
||||||
|
store.put({id: 5, name: "foo"});
|
||||||
|
store.put({id: 6, name: "bar"});
|
||||||
|
store.put({id: 7, name: "bazzz"});
|
||||||
|
await delay();
|
||||||
|
console.log("reading the foos");
|
||||||
|
console.log("5", await reqAsPromise(store.get(5)));
|
||||||
|
console.log("6", await reqAsPromise(store.get(6)));
|
||||||
|
console.log("7", await reqAsPromise(store.get(7)));
|
||||||
|
// await txnAsPromise(txn);
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
console.error(err);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
main();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
Reference in a new issue