【发布时间】:2016-05-05 01:36:56
【问题描述】:
来自 Java 背景的我现在正试图围绕 Javascript 的异步特性来思考。我在我的代码中使用 Promise 来做到这一点,直到现在一切都像一个魅力,但现在我有一个概念性问题,即使在多次阅读 Promise/A+ 规范后也没有找到明确的答案。
我的要求是:我有一个修改共享对象的方法,将更新存储在 PouchDB 中,然后再将其读回,以便从数据库中获取更新的修订 id 字段(乐观锁定)。在 Pouch 中存储和更新数据是异步的(为简洁起见,我省略了存储“this”以从 Promise 中调用方法):
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 被再次读取之前,没有在 _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);
});
});
}
我认为如果履行承诺(调用 done())将同步调用下一个 then() 函数,它应该可以正常工作,但我无法找到明确的答案是否是这种情况。
非常感谢任何澄清,并感谢您的帮助。
【问题讨论】:
-
我有消息要告诉你。 Promise 并不能帮助您编写一点原子代码。事实上,它们甚至可能使事情变得更糟,因为每个
.then()处理程序都保证是异步的,这意味着在调用.then()处理程序之前可以执行其他事情。看来您在这里的理解有些偏离基础,您的设计逻辑只是走错了方向。 -
在更新值后真正获得原子修订 ID 的唯一方法是让数据库从写入调用返回修订 ID(将原子操作的责任放在数据库本身可以做到的地方)安全实施)。假设这是一个多用户数据库,在您读回修订 ID 之前,其他任何事情都允许对数据库进行其他更改。如果您只是想保护自己的代码不向数据库写入其他内容(而不是多用户),那么您将必须实现某种标志,所有代码都会检查。
-
@jfriend00 我知道
.then()是异步执行的,这就是为什么我想等待最后一个then()(put()的“返回”)完成后再解析@987654328 @作为一个整体。在这种情况下,数据库不是多用户的,因为它是本地 PouchDB。我只是想确保setValue()执行以顺序方式运行。调用多次是完全没问题的,只要里面的操作按顺序排队执行即可。 -
@mrmcgreg - 我不确定这是否正确,因为当我调用
done()时,承诺已经实现,不是更早,不是吗,所以从 Promise 的构造函数中返回一些东西不会对我有任何好处。也许您可以再次检查我的代码,当我执行put()时,我不在then()内(请参阅下面的 Dark Falcon 的回复)。这当然是一个简化的例子,真实的代码将更新/检索代码提取到一个单独的方法中,其他方法调用。
标签: javascript asynchronous pouchdb