使用 Promise 在 Javascript 中创建 "atomic" 代码块
Using a Promise to create "atomic" blocks of code in Javascript
来自 Java 的背景,我现在正试图围绕 Java 脚本的异步性质进行思考。我在我的代码中使用 promises 来做到这一点,直到现在一切都像一个魅力,但现在我有一个概念性问题,即使在多次阅读 Promise/A+ 规范后也没有找到明确的答案。
我的要求是这样的:我有一个修改共享对象的方法,将更新存储在 PouchDB 中,然后读回它以便从数据库中获取更新的修订 ID 字段(乐观锁定)。在 Pouch 中存储和更新数据是异步的(为了简洁起见,我省略了存储 "this" 以从 promises 中调用方法):
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 写入数据库之前,在它被再次读取之前没有设置其他键。是否 (a) 甚至有可能另一个 setValue() 调用正在执行 put() (具有过时的修订 ID),而来自 Pouch 的 get() 调用尚未执行(考虑到 JS 正在使用的消息队列方法) ) 和 (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);
});
});
}
我认为如果 fulfilling a promise(调用 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;
});
});
}
来自 Java 的背景,我现在正试图围绕 Java 脚本的异步性质进行思考。我在我的代码中使用 promises 来做到这一点,直到现在一切都像一个魅力,但现在我有一个概念性问题,即使在多次阅读 Promise/A+ 规范后也没有找到明确的答案。
我的要求是这样的:我有一个修改共享对象的方法,将更新存储在 PouchDB 中,然后读回它以便从数据库中获取更新的修订 ID 字段(乐观锁定)。在 Pouch 中存储和更新数据是异步的(为了简洁起见,我省略了存储 "this" 以从 promises 中调用方法):
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 写入数据库之前,在它被再次读取之前没有设置其他键。是否 (a) 甚至有可能另一个 setValue() 调用正在执行 put() (具有过时的修订 ID),而来自 Pouch 的 get() 调用尚未执行(考虑到 JS 正在使用的消息队列方法) ) 和 (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);
});
});
}
我认为如果 fulfilling a promise(调用 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;
});
});
}