使用Promise来创建“;原子“;Javascript中的代码块

Using a Promise to create "atomic" blocks of code in Javascript

本文关键字:代码 Javascript 原子 创建 Promise 使用      更新时间:2023-09-26

我来自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被写入数据库时,在它被再次读取之前,没有在它上设置其他键。(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);
        });
    });
}

我认为如果实现一个promise(调用done())将同步调用下一个then()函数,它应该可以正常工作,但我无法找到是否是这种情况的确切答案。

如有任何澄清,我们将不胜感激,并感谢您的帮助。

正如您在这里尝试做的那样,Chaining promise确实如预期的那样工作,但我不认为有任何保证done被同步调用。我认为您的代码可以工作,但其中有一些反模式。我建议简化以避免显式创建promise。

还要考虑:如果您连续调用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;
        });
    });
}