【问题标题】:Ajax Request Wait Until First AJAX Call not completeAjax 请求等待直到第一个 AJAX 调用未完成
【发布时间】:2016-07-03 08:02:39
【问题描述】:

我有下面的自动保存代码,但是我有很多 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);
            }
        },
    });
}

【问题讨论】:

  • ajax 是异步的。你需要坚持运行它们吗?
  • 一旦第一个 Ajax 请求完成,然后第二个 Ajax 请求运行。我需要在我的代码中使用 .finish() Jquery 或 .ajaxComplete() Jquery?
  • 触发第二个ajax请求的代码在哪里,我在setTimeout调用中只看到一个。

标签: jquery ajax


【解决方案1】:

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

我猜你可以使用下一个方法:在发送 ajax 之前从表单元素中取消绑定侦听器,并在 ajax 完成时将它们绑定回来

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

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

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 失败,您不会错过绑定侦听器...

【讨论】:

  • 将 jqXHR.success 替换为 jqXHR.done 后不起作用,此方法中的数据未到达 .done()
  • @vikas 很奇怪,感谢您的评论,我已经更新了答案,只是指出那一刻(successerorr 的弃用)并添加了链接。
【解决方案2】:

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

我不希望同时运行多个 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);
            }
        },
    });
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-20
    • 2014-02-19
    • 2013-03-27
    • 1970-01-01
    • 2016-12-12
    • 2014-10-19
    • 1970-01-01
    • 2012-11-02
    相关资源
    最近更新 更多