嵌套的承诺函数

时间:2017-01-06 03:15:15

标签: javascript jquery promise

我有一个按钮,我想跟踪用户按下它,如果跟踪ajax调用返回数据,然后执行一个承诺,当这一切都完成后,继续按钮事件。

以下是我到目前为止所做的事情,但按钮事件和第二个承诺同时发生。按钮事件不等待第二个承诺解决

  • 点击按钮
  • AJAX调用记录事件
  • 如果AJAX没有回复问题,请提示你好。
  • 如果AJAX调用返回一个问题,那么构建并打开模态,当模态关闭时,然后警告你好。
$('.my_button').on('click', function() {
    ui_tracking('button_1').then(function () {
        alert('Hello');
    });
});

function ui_tracking(type, payload) {
    var deferred = $.Deferred();

    var log_action = function () {
        $.ajax({
            url: '/api/submit_action',
            type: 'POST',
            dataType: 'json',
            data: {
                type: type,
                payload: JSON.stringify(payload)
            },
            success: function(results, textStatus, xhr) {
                if (typeof(results) !== 'undefined' && results !== null) {
                    if (typeof(results.data) !== 'undefined' && results.data !== null) {
                        if (results.data.question) {
                            startQuestion(results.data.question).then(function () {
                                deferred.resolve();
                            }, function() {
                                deferred.reject();
                            });
                        }
                    }
                }

                deferred.resolve();
            },
            error: function (xhr, textStatus, errorThrown) {
                deferred.reject();
            }
        });
    };

    log_action();

    return deferred.promise();
}

function startQuestion(question_data) {
    var deferred = $.Deferred();

    var openQuestion = function () {
        $('#question-modal .modal-body .question').html(question_data.question).attr('data-question-id', question_data.id);

        $('#question-modal').modal('show').on('hidden.bs.modal', function (e) {
            deferred.resolve();
            $('#question-modal').unbind('hidden.bs.modal');
        });
    };

    openQuestion();
    return deferred.promise();
}

SF

2 个答案:

答案 0 :(得分:0)

您的成功:立即回调deferred.resolve();(最后,在if条件之后)

    success: function(results, textStatus, xhr) {
        if (typeof(results) !== 'undefined' && results !== null) {
            if (typeof(results.data) !== 'undefined' && results.data !== null) {
                if (results.data.question) {
                    startQuestion(results.data.question).then(function () {
                        deferred.resolve();
                    }, function() {
                        deferred.reject();
                    });
                }
            }
        }
        // this gets called regardless of the above conditions!
        deferred.resolve();

知道$ .ajax返回一个(jQuery)Promise,我相信你可以简化ui_tracking函数,如下所示:

function ui_tracking(type, payload) {
    return $.ajax({
        url: '/api/submit_action',
        type: 'POST',
        dataType: 'json',
        data: {
            type: type,
            payload: JSON.stringify(payload)
        }
    }).then(function(results) {
        if (results && results.data && results.data.question) {
            return startQuestion(results.data.question);
        }
    });
}

在上面。然后,如果条件不满足,则返回undefined ...基本上与使用deferred.resolve()时相同 - 返回的Promise将被解析为{ {1}}一旦ajax完成

但是,如果条件都满足,则返回是undefined返回的Promise - 这意味着返回的Promise将是startQuestion返回的Promise - 因此您的代码将等待承诺在继续之前解决

此外,不需要简单地返回被拒绝的承诺的错误处理 - 让外部调用处理错误

或者,您可以将整个批次写为

startQuestion

当然逻辑已经发生了变化,所以可能并不完全是你想要的

答案 1 :(得分:0)

您可以封装每个"步骤"在函数中返回一个promise(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)然后" chain"他们。

这是一篇关于在一系列中执行承诺的好文章:http://www.datchley.name/promise-patterns-anti-patterns/#executingpromisesinseries(你可能需要为你的承诺提供一个polyfill:https://github.com/stefanpenner/es6-promise