Jquery When和Deferred对象,破坏函数流

时间:2015-04-13 18:52:01

标签: javascript jquery jquery-deferred .when

我正在使用$ .when和.done来确保在保存数据后关闭窗口。但是,这似乎没有按预期工作。

工作流程是,用户点击“保存并关闭”按钮,该按钮应首先保存数据,触发打印并关闭窗口。但保存数据和关闭窗口同时发生,导致打印失败。

我已经阅读过when..then和deferred对象。试图在这里实现以下代码,有时它可以工作,但大部分时间它会破坏。

$("#btnSaveAndClose").click(function (event) {
    $.when(zSaveSomeData()).done(function (value) {
        zCloseMyWindow();
    });
});

function zSaveSomeData() {
    return zSaveMasterData(masterdata, function () {  
        return zSaveDetailData();
    });
};

function zSaveMasterData(masterdata, fnAfterSave) {
    return $.ajax({
        type: 'POST',
        contentType: 'application/json',
        url: '/api/masterdata/',
        data: JSON.stringify(masterdata),
        success: function (data) {
            fnAfterSave();
        }
    });
};

function zSaveDetailData() {
    var selectedDataGroups;
    // some logic here

    zSaveDetails(selectedDataGroups);

};

function zSaveDetails(selectedDataGroups) {
    var deferred = $.Deferred();
    $.ajax({
        type: 'POST',
        contentType: 'application/json',
        url: '/api/detaildata/',
        data: JSON.stringify(selectedDataGroups),
        success: function (data) {
            var printableGroupIDs = [];
            $.each(data, function () {
                if (this.IsPrintable)
                    printableGroupIDs.push(this.ID);
            });

            if (printableGroupIDs.length > 0) {
                zPrintGroups(printableGroupIDs);
            }
            deferred.resolve('done');
        }
    });

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

function zPrintGroups(newGroupIDs) {
    // calls external program to print groups

};

function zCloseWindow() {
    window.close();
};

function zAuditSave() {
    $.ajax({
        type: 'POST',
        contentType: 'application/json',
        url: '/api/audit'
        success: function (data) {

        }
    });
};

唯一的问题是,save会将其他方法调用到同一个master和details数据中。还有几个ajax调用。一个不寻常的事情是,在保存数据之后,调用VB代码实际上会触发打印。我很困惑为什么在执行其他方法之前会关闭窗口。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:2)

对我来说,代码过分分为函数,有些代码只是面向其他代码。

我希望将点击处理程序视为一个综合的主程序,它会对三个承诺返回函数zSaveMasterData()zSaveDetails()zAuditSave()进行排序,然后关闭窗口。因此,一些当前函数将被click处理程序包含。

$("#btnSaveAndClose").click(function(event) {
    zSaveMasterData(masterdata).then(function() {
        var selectedDataGroups;
        /* some logic here */
        var detailsSaved = zSaveDetails(selectedDataGroups).then(function(data) {
            var printableGroupIDs = $.map(data, function (obj) {
                return obj.IsPrintable ? obj.ID : null;
            });
            if (printableGroupIDs.length > 0) {
                // calls external program to print groups
            }
        });
        // Here, it is assumed that zSaveDetails() and zAuditSave() can be performed in parallel.
        // If the calls need to be sequential, then the code will be slightly different.            
        return $.when(detailsSaved, zAuditSave());
    }).then(function() {
        window.close();
    });
});

function zSaveMasterData(masterdata) {
    return $.ajax({
        type: 'POST',
        url: '/api/masterdata/',
        contentType: 'application/json',
        data: JSON.stringify(masterdata),
    });
};

function zSaveDetails(selectedDataGroups) {
    return $.ajax({
        type: 'POST',
        contentType: 'application/json',
        url: '/api/detaildata/',
        data: JSON.stringify(selectedDataGroups)
    });
};

function zAuditSave() {
    return $.ajax({
        type: 'POST',
        contentType: 'application/json',
        url: '/api/audit'
    });
};

注意带有ajax调用的三个函数的返回值。这些回报对于测序过程至关重要。

一个可能更大的问题,问题中没有解决(也不是在这个答案中)是如何从错误中恢复。据推测,如果保存顺序部分失败,数据库将不一致。抛弃这种客户端排序方法以支持客户端看作单个操作的服务器端事务可能会更好。

答案 1 :(得分:0)

此处的问题是您的代码并不依赖于fnAfterSave()何时完成。

简短回答:不要混用success方法,callbackspromises - 使用一种模式并坚持下去 - 最简单的模式是{{1 }}

promises

答案 2 :(得分:0)

似乎你的问题是你在ajax success回调中做异步事情。收到回复后,$.ajax返回的承诺仍会立即解决 - 并在异步done完成之前执行zSaveDetailData()回调。

因此,要链接异步操作,始终使用then 。即使对于同步动作也使用它,它使序列清晰。

当您使用承诺时,不要使用success回调。你也don't need deferreds。您可能也希望查看these generic rules,尤其是您永远不会忘记要等待的异步函数的return承诺。

$("#btnSaveAndClose").click(function (event) {
    zSaveSomeData().then(zCloseMyWindow);
});

function zSaveSomeData() {
    return zSaveMasterData(masterdata).then(zSaveDetailData);
}

function zSaveMasterData(masterdata) {
    return $.ajax({
        type: 'POST',
        contentType: 'application/json',
        url: '/api/masterdata/',
        data: JSON.stringify(masterdata),
    });
}

function zSaveDetailData() {
    var selectedDataGroups;
    // some logic here

    return zSaveDetails(selectedDataGroups);
//  ^^^^^^
}

function zSaveOrderGroups(selectedDataGroups) {
    return $.ajax({
//  ^^^^^^
        type: 'POST',
        contentType: 'application/json',
        url: '/api/detaildata/',
        data: JSON.stringify(selectedDataGroups)
    }).then(function(data) {
//    ^^^^^^^^^^^^^^^^^^^^^^
        var printableGroupIDs = [];
        $.each(data, function () {
            if (this.IsPrintable)
                 printableGroupIDs.push(this.ID);
        });
        if (printableGroupIDs.length > 0) {
            return zPrintGroups(printableGroupIDs);
//          ^^^^^^
        }
    }).then(zAuditSave);
//    ^^^^^^^^^^^^^^^^^
}

function zPrintGroups(newGroupIDs) {
    // calls external program to print groups
}

function zCloseWindow() {
    window.close();
}

function zAuditSave() {
    return $.ajax({
//  ^^^^^^
        type: 'POST',
        contentType: 'application/json',
        url: '/api/audit'
    });
}