控制承诺执行顺序

时间:2015-03-06 20:14:29

标签: javascript promise

使用promises构建高度交互的UI我有很多乐趣。但是,我遇到了一个棘手的情况。我有一个函数返回执行服务器更新的promise。我想使用后续承诺处理程序来更新客户端模型,然后向UI发出更新事件。这是我的代码:

function updateServer (action) {
    return $.post(URL, { action: action })
        .fail(function (error) {
            console.log(error);
        });
}

 // An example action that might affect the server
_this.freeze = function (mode) {
    updateServer("freeze").done(function (data) {
        _this.model.data.status = data.status;
    })
    .done(function () {
        $(window).trigger(Events.UpdateUI);
    });
};

您会注意到我必须在freeze命令中发出更新事件。我宁愿在updateServer函数中这样做,以避免重复每个控制方法中的代码。

我想通过将模型更新函数作为参数传递给updateServer来实现这一点,但是,它似乎违反了我认为的承诺精神:

function updateServer (action, fn) {
    return $.post(URL, { action: action })
        .done(fn)
        .done(function () {
            $(window).trigger(Events.UpdateUI);
        })
        .fail(function (error) {
            console.log(error);
        });
}

 // An example action that might affect the server
_this.freeze = function (mode) {
    updateServer("freeze", function (data) {
        _this.model.data.status = data.status;
    });
};

我认为另一种方法是设计一种优先级较低的完成处理程序,这样就可以使我保持承诺可组合性的精神。我错过了什么,或者我是以“正确的方式”做到这一点吗?

谢谢你们!

2 个答案:

答案 0 :(得分:1)

您不应该尝试在用于与服务器通信的函数内更新UI。这是Separation of Concerns的对立面。

如果你想要一种确保这些任务总是一起执行的方法,你可以创建另一个将这两个动作连接在一起并返回promise的函数,以便它可以被进一步链接。

编辑:根据您的评论,现在很清楚您希望将数据检索和UI更新作为一个整体保存在一起,但在之间执行另一个操作。在那种情况下,我会说解决方案是传递一个函数。只要您没有使用回调来控制整个执行流程,这仍然符合承诺的精神:

function updateServer (action) {
    return $.post(URL, { action: action })
    .fail(function (error) {
        console.log(error);
    });
}

function updateUI () {
    $(window).trigger(Events.UpdateUI);
}   

function updateServerAndRefreshUI (action, updateModel) {
    return updateServer(action)
    .done(updateModel)
    .done(updateUI);
}

 // An example action that might affect the server
_this.freeze = function (mode) {
    updateServerAndRefreshUI("freeze", function (data) {
        _this.model.data.status = data.status;
    });
};

答案 1 :(得分:1)

我想你会想要使用一个帮助你整个行动的辅助函数:

function updateUIwith(result) {
    return result.then(function() {
        $(window).trigger(Events.UpdateUI);
    }).fail(function(error) {
        console.log(error);
    });
}

现在你只需要写

function updateServer(action) {
    return $.post(URL, {action: action})
}

// An example action that might affect the server
_this.freeze = function(mode) {
    updateUIwith(updateServer("freeze").then(function(data) {
        _this.model.data.status = data.status;
    }));
};