I feel like this is a pretty mundane thing to do. I want to update an object in an IndexedDB database and then run some code after which uses the updated values.
What I originally did was just run my callback function after calling cursor.update
, which works in Firefox. But it fails in Chrome, the update doesn't happen before the following code is run. This is likely a race condition, since (as I understand it) updates are asynchronous.
So then I thought I should use the onsuccess
signal of cursor.update
to call my callback function. But much to my surprise, that also doesn't seem to work in Chrome!
Some example code which you can run on jsFiddle... although amusingly this seems to crash in Firefox in jsFiddle for some reason, but Chrome works fine; for Firefox you can run it locally and it works (this produces output on the JavaScript console in your browser):
<html>
<head>
<script>
var db, request;
request = indexedDB.open("test", 1);
request.onupgradeneeded = function (event) {
var i, leagueStore, teams, teamStore;
db = event.target.result;
objectStore = db.createObjectStore("objects", {keyPath: "id"});
};
request.onsuccess = function (event) {
db = request.result;
// Add some dummy data
db.transaction("objects", "readwrite").objectStore("objects").put({
id: 0,
value: 42
});
// Update data
db.transaction("objects", "readwrite").objectStore("objects").openCursor(0).onsuccess = function (event) {
var cursor, object;
cursor = event.target.result;
object = cursor.value;
object.value = 43;
cursor.update(object).onsuccess = function (event) {
db.transaction("objects").objectStore("objects").get(0).onsuccess = function (event) {
console.log("Cursor update onsuccess event:");
console.log(event.target.result);
};
};
// Read back updated data
db.transaction("objects").objectStore("objects").get(0).onsuccess = function (event) {
console.log("The line after the cursor update:");
console.log(event.target.result);
};
// Wait a little bit, then read it back
setTimeout(function () {
db.transaction("objects").objectStore("objects").get(0).onsuccess = function (event) {
console.log("After an additional delay via setTimeout:");
console.log(event.target.result);
};
}, 100);
};
};
</script>
</head>
</html>
Observed behavior (all on Ubuntu 12.10, FWIW):
In Firefox 19 (current stable version), all three logged objects are identical, with value
set to 43:
The line after the cursor update:
Object {id: 0, value: 43}
Cursor update onsuccess event:
Object {id: 0, value: 43}
After an additional delay via setTimeout:
Object {id: 0, value: 43}
In Chrome 25 (current stable version) and 27 (current unstable version), I usually get this output:
The line after the cursor update:
Object {id: 0, value: 42}
Cursor update onsuccess event:
Object {id: 0, value: 42}
After an additional delay via setTimeout:
Object {id: 0, value: 43}
Sometimes one of the first two outputs is updated to 43, but it's usually a 42.
So again, my question is... how can I run something after the update is actually finished? (That is, without relying on some ridiculous arbitrary delay induced with setTimeout
.)
Alternative question: Am I doing something wrong, or is this a bug in Chrome?
Side question: If anyone has IE 10, I wonder how it behaves in this situation..
See Question&Answers more detail:
os