使用Promise创建" atomic" Javascript

时间:2016-05-04 17:10:27

标签: javascript asynchronous pouchdb

来自Java背景我现在试图围绕Javascript的异步特性。我在我的代码中使用promises来做到这一点,直到现在一切都像一个魅力,但现在我有一个概念性的问题,即使多次阅读Promise / A +规范后也没有找到明确的答案。

我的要求是这样的:我有一个修改共享对象的方法,将更新存储在PouchDB中并随后将其读回,以便从db(乐观锁定)获取更新的修订版ID字段。在Pouch中存储和更新数据是异步的(我省略了存储"这个"为了简洁而在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)如果可能的话,以下解决方案是安全的(它在我的测试中工作,但因为我不知道我的测试是否正在考虑所有可能性......;存储"这个"再次被省略):

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())将同步调用next then()函数它应该正常工作,但是我无法找到明确的答案是否是这种情况。

非常感谢任何澄清,感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

你在这里尝试做的链接确实确实按预期工作,但我不相信有done被同步调用的保证。我认为你的代码可行,但你有一些反模式。我建议简化以避免明确创建承诺。

还要考虑一下:如果你连续4次拨打setValue,那么到服务器的往返次数应该是多少?这样做会使它成为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;
        });
    });
}