Coming from a Java background I am now trying to wrap my mind around the asynchronous nature of Javascript. I use promises in my code to do this and until now everything works like a charm, but now I am having a conceptual question and didn't find a definitive answer even after reading the Promise/A+ spec multiple times.
My requirements are this: I have a method that modifies a shared object, stores the update in a PouchDB and reads it back afterwards in order to get an updated revision id field from the db (optimistic locking). Storing and updating the data in Pouch is asynchronous (I am omitting storing "this" to call the methods from within the promises for brevity):
var _doc = ...;
var _pouch = new PouchDB(...);
function setValue(key, value) {
_doc[key] = value;
_pouch.put(_doc)
.then(function() {
return _pouch.get(_doc._id);
})
.then(function(updatedDoc) {
_doc = updatedDoc;
});
}
Now, I want to make sure that no other key is set on _doc while it is being written to the db before it has been read again. Is it (a) even possible that another setValue() call is executing a put() (with an outdated revision id) while the get() call from Pouch has not been executed (given the message-queue-approach that JS is using) and (b) if it is possible, is the following solution fail-safe (it is working in my tests, but since I don't know if my tests are considering all possibilities...; storing "this" is again omitted):
var _doc = ...;
var _pouch = new PouchDB(...);
var _updatePromise;
function setValue(key, value) {
if (_updatePromise == null) {
setValueInternal(key, value);
}
else {
// make sure the previous setValue() call is executed completely before
// starting another one...
_updatePromise.then(function() {
setValueInternal(key, value);
});
}
}
function setValueInternal(key, value) {
_doc[key] = value;
_updatePromise = new Promise(function(done, reject) {
_pouch.put(_doc)
.then(function() {
return _pouch.get(_doc._id);
})
.then(function(updatedDoc) {
_doc = updatedDoc;
_updatePromise = null;
done();
})
catch(function(error) {
_updatePromise = null;
reject(error);
});
});
}
I think it should work correctly if fulfilling a promise (calling done()) will synchronously call the next then() function, but I am unable to find a definitive answer whether this is the case.
Any clarification is greatly appreciated and thanks for your help.
.then()handler is guaranteed to be async which means other things can execute before a.then()handler is called. It appears your understanding here is way off base and your design logic is just going the wrong direction..then()is executed asynchronously, that's why I want to wait for the lastthen()(the "return" of theput()) to finish before I resolve_updatePromiseas a whole. The DB is not multi-user in this case, because it is a local PouchDB. I just wanted to make sure thatsetValue()executions are running in a sequential way. It is perfectly ok that it is called multiple times as long as the operations in it are queued to execute in order.done(), not earlier, isn't it, so returning something from within the constructor of the Promise won't do any good to me. Perhaps you can check my code again, I am not inside athen()when I do theput()(see Dark Falcon's response below). This is of course a simplified example, the real code extracted the update/retrieve code into a separate method that other methods call.