来自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;
        });
    });
}

10-05 20:54
查看更多