来自Java背景,现在我想围绕Javascript的异步特性来思考。我在代码中使用了promises,直到现在一切都像魅力一样,但是现在我遇到了一个概念性的问题,即使多次阅读Promise / A +规范也没有找到明确的答案。
我的要求是:我有一个方法可以修改共享库,将更新存储在PouchDB中,然后将其读取回去,以便从数据库中获取更新的修订ID字段(乐观锁定)。在Pouch中存储和更新数据是异步的(我省略存储“ this”以从简短的承诺中调用方法):
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;
});
}
现在,我要确保在将_doc写入db之前,在_doc上未设置其他任何键,然后再次读取它。 (a)甚至有可能在没有执行来自Pouch的get()调用的情况下(考虑到JS正在使用的消息队列方法),另一个setValue()调用正在执行put()(具有过期的修订版id) )和(b)如果可能,以下解决方案是否是故障安全的(它在我的测试中有效,但是由于我不知道我的测试是否正在考虑所有可能性...;因此再次省略存储“ this” ):
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);
});
});
}
我认为,如果兑现承诺(调用done())将同步调用下一个then()函数,则它应该可以正常工作,但是无论如何我都无法找到确切的答案。
任何澄清将不胜感激,并感谢您的帮助。
最佳答案
在您尝试在此处进行链接时,诺言确实可以按预期工作,但是我不相信可以保证done
被同步调用。我认为您的代码可以使用,但是其中包含一些反模式。我建议进行简化,以避免显式创建承诺。
还要考虑一下:如果您连续调用setValue
4次,那么该服务器应该往返多少次?这样做需要4个步骤。您想将它们分为1个还是2个?
每个setValue
一次往返:
var _doc = ...;
var _pouch = new PouchDB(...);
var _updatePromise = Promise.resolve();
function setValue(key, value) {
// make sure the previous setValue() call is executed completely before
// starting another one...
_updatePromise = _updatePromise.then(function() {
_doc[key] = value;
return _pouch.put(_doc)
.then(function() {
return _pouch.get(_doc._id);
})
.then(function(updatedDoc) {
_doc = updatedDoc;
});
});
}