Ajax请求等待直到第一个AJAX调用未完成

时间:2016-03-17 05:53:43

标签: jquery ajax

我有以下代码用于自动保存,但我同时遇到大量Ajax请求,我想等待Ajax请求直到第一个Ajax请求未完成

window.submitting = false;
$('form#AddForm').submit(function() {
    window.submitting = true;
});

var timeoutId;
$('form input, form textarea, form select').bind('input propertychange change', function() {
    console.log('Change');

    if (window.submitting)
        return false;

    clearTimeout(timeoutId);
    timeoutId = setTimeout(function() {
        // Runs 5 second (5000 ms)   
        autoSave();
    }, 5000);
});

function autoSave() {
    $.ajax({
        type: "POST",
        data: $('form#AddForm').serialize() + '&autosave=true',
        beforeSend: function(xhr) {
            // Let them know we are saving
            console.log('Saving........');
        },
        success: function(data) {
            var jqObj = jQuery(data); // Ajax call here.
            var ProductId = jqObj.find("#ProductId").val();
            var url = $(location).attr('href');
            var split = url.split("add");
            if (ProductId) {
                history.pushState({}, null, split[0] + "add/" + ProductId);
                $('#ProductId').val(ProductId);
                $('form#AddForm').attr('action', '/dataproducts/add/' + ProductId);
            }
        },
    });
}

2 个答案:

答案 0 :(得分:3)

看起来我已经抓住了你的问题。如果用户在表单元素上触发了很少的更改事件,则会创建新的ajax请求,但不应该在上一个处理过程中。

我猜您可以在发送ajax之前使用下一种方法:取消绑定侦听器,然后在完成ajax时将它们绑定

关于绑定/解除绑定,有一个很好的答案:Best way to remove an event handler in jQuery?

所以基本上你必须进行litle重构并添加几行代码:

window.submitting = false;
$('form#ProductAddForm').submit(function() {
    window.submitting = true;
});

var timeoutId;
var saveHandler = function() {
    console.log('Change');

    if (window.submitting)
        return false;

    clearTimeout(timeoutId);
    timeoutId = setTimeout(function() {
        // Runs 5 second (5000 ms)
        autoSave();
    }, 5000);
};

$('form input, form textarea, form select').bind('input propertychange change', saveHandler);

function autoSave() {
    // unbind events
    $('form input, form textarea, form select').unbind('input propertychange change')
    $.ajax({
        type: "POST",
        data: $('form#ProductAddForm').serialize() + '&autosave=true',
        beforeSend: function(xhr) {
            // Let them know we are saving
            console.log('Saving........');
        },
        success: function(data) {
            var jqObj = jQuery(data); // Ajax call here.
            var ProductId = jqObj.find("#ProductId").val();
            var url = $(location).attr('href');
            var split = url.split("add");
            if (ProductId) {
                history.pushState({}, null, split[0] + "add/" + ProductId);
                $('#ProductId').val(ProductId);
                $('form#ProductAddForm').attr('action', '/account/products/add/' + ProductId);
            }
            // bind events back
            $('form input, form textarea, form select').bind('input propertychange change', saveHandler);
        },
        error: function{
            // bind events back even if reqeust fail
            $('form input, form textarea, form select').bind('input propertychange change', saveHandler);
        }
    });
}

注意 jqXHR.successjqXHR.error已弃用,有关详细信息,请参阅$.ajax。我还添加了error方法,因为如果ajax失败,你不能错过绑定侦听器......

答案 1 :(得分:0)

我可能误解了这个问题,但我读到了这样的问题:

  

我不希望同时运行多个ajax请求。但   请求完成后,我想运行下一个。

您可以使用ajaxManager,如jAndy所建议的那样:Queue ajax requests using jQuery.queue()

var ajaxManager = (function() {
     var requests = [];

     return {
        addReq:  function(opt) {
            requests.push(opt);
        },
        removeReq:  function(opt) {
            if( $.inArray(opt, requests) > -1 )
                requests.splice($.inArray(opt, requests), 1);
        },
        run: function() {
            var self = this,
                oriSuc;

            if( requests.length ) {
                oriSuc = requests[0].complete;

                requests[0].complete = function() {
                     if( typeof(oriSuc) === 'function' ) oriSuc();
                     requests.shift();
                     self.run.apply(self, []);
                };   

                $.ajax(requests[0]);
            } else {
              self.tid = setTimeout(function() {
                 self.run.apply(self, []);
              }, 1000);
            }
        },
        stop:  function() {
            requests = [];
            clearTimeout(this.tid);
        }
     };
}());

并在您的代码中使用它:

ajaxManager.run(); 

function autoSave() {
    ajaxManager.addReq({
        type: "POST",
        data: $('form#ProductAddForm').serialize() + '&autosave=true',
        beforeSend: function(xhr) {
            // Let them know we are saving
            console.log('Saving........');
        },
        success: function(data) {
            var jqObj = jQuery(data); // Ajax call here.
            var ProductId = jqObj.find("#ProductId").val();
            var url = $(location).attr('href');
            var split = url.split("add");
            if (ProductId) {
                history.pushState({}, null, split[0] + "add/" + ProductId);
                $('#ProductId').val(ProductId);
                $('form#ProductAddForm').attr('action', '/account/products/add/' + ProductId);
            }
        },
    });
}

这样您就可以对不同的请求进行排队。但是,通过代码,您似乎总是发送整个表单。那么,如果下一个请求会发布更准确的值,为什么第一个请求会完成呢?显然有理由说你可能想发布每一个变化。但如果没有,你可以取消之前的请求并发送另一个请求。

var xhr;

function autoSave() {
    if(xhr){
       //TODO: Check if there is a current call.
       // abort call.
       xhr.abort();
    }
    xhr = $.ajax({
        type: "POST",
        data: $('form#ProductAddForm').serialize() + '&autosave=true',
        beforeSend: function(xhr) {
            // Let them know we are saving
            console.log('Saving........');
        },
        success: function(data) {
            var jqObj = jQuery(data); // Ajax call here.
            var ProductId = jqObj.find("#ProductId").val();
            var url = $(location).attr('href');
            var split = url.split("add");
            if (ProductId) {
                history.pushState({}, null, split[0] + "add/" + ProductId);
                $('#ProductId').val(ProductId);
                $('form#ProductAddForm').attr('action', '/account/products/add/' + ProductId);
            }
        },
    });
}