Ajax请求等到第一次AJAX调用未完成

时间:2022-08-23 18:00:12

I have below code for auto saving but i have problem lot of Ajax request firing on same time, i want to wait Ajax request Until first Ajax request not complete

我有以下代码用于自动保存,但我同时有很多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 个解决方案

#1


3  

It looks like i've catch your problem. If user triggers few change events on form elements new ajax request would be created, but shouldn't until previous are in process.

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

My guess you can use next approach: unbind listeners from form elements before you send ajax and bind them back when ajax would be completed.

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

There are an excellent answer on SO regarding binding/unbinding: Best way to remove an event handler in jQuery?

关于绑定/解绑定的SO有一个很好的答案:在jQuery中删除事件处理程序的最佳方法是什么?

So basically you have to make a litle refactoring and add few lines of code:

所以基本上你必须进行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);
        }
    });
}

Note jqXHR.success and jqXHR.error is deprecated, see $.ajax for more info. Also i've added error method, because you cannot miss binding listeners if ajax fails ...

注意不推荐使用jqXHR.success和jqXHR.error,有关详细信息,请参阅$ .ajax。此外,我添加了错误方法,因为如果ajax失败,你不能错过绑定侦听器...

#2


0  

I might have misunderstood the question, but I read the question like this:

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

I don't want more than one ajax requests to run at the same time. But when the request is finished I want to run the next one.

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

You can use an ajaxManager, like suggested by jAndy here: Queue ajax requests using jQuery.queue()

您可以使用ajaxManager,如jAndy在此建议:使用jQuery.queue()排队ajax请求

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);
        }
     };
}());

And to use it in your code:

并在您的代码中使用它:

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);
            }
        },
    });
}

This way you can queue different requests. However, by the code it seems that you always send the entire form. So why should the first request finish, if the next request will post a more accurate value? There can obviously be reason why you may want to post every change. But if not, you could cancel the previous request and send another one instead.

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

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);
            }
        },
    });
}

#1


3  

It looks like i've catch your problem. If user triggers few change events on form elements new ajax request would be created, but shouldn't until previous are in process.

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

My guess you can use next approach: unbind listeners from form elements before you send ajax and bind them back when ajax would be completed.

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

There are an excellent answer on SO regarding binding/unbinding: Best way to remove an event handler in jQuery?

关于绑定/解绑定的SO有一个很好的答案:在jQuery中删除事件处理程序的最佳方法是什么?

So basically you have to make a litle refactoring and add few lines of code:

所以基本上你必须进行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);
        }
    });
}

Note jqXHR.success and jqXHR.error is deprecated, see $.ajax for more info. Also i've added error method, because you cannot miss binding listeners if ajax fails ...

注意不推荐使用jqXHR.success和jqXHR.error,有关详细信息,请参阅$ .ajax。此外,我添加了错误方法,因为如果ajax失败,你不能错过绑定侦听器...

#2


0  

I might have misunderstood the question, but I read the question like this:

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

I don't want more than one ajax requests to run at the same time. But when the request is finished I want to run the next one.

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

You can use an ajaxManager, like suggested by jAndy here: Queue ajax requests using jQuery.queue()

您可以使用ajaxManager,如jAndy在此建议:使用jQuery.queue()排队ajax请求

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);
        }
     };
}());

And to use it in your code:

并在您的代码中使用它:

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);
            }
        },
    });
}

This way you can queue different requests. However, by the code it seems that you always send the entire form. So why should the first request finish, if the next request will post a more accurate value? There can obviously be reason why you may want to post every change. But if not, you could cancel the previous request and send another one instead.

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

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);
            }
        },
    });
}