简体   繁体   English

防止AJAX队列阻止浏览器

[英]Prevent AJAX Queue from blocking browser

Note: simplified example.. 注意:简化示例

I've got a page with 1000 table rows. 我有一个包含1000个表行的页面。 For each row, i need to "do some work" on the server via an AJAX call, then in the callback, update that table row saying done. 对于每一行,我需要通过AJAX调用在服务器上“做一些工作”,然后在回调中更新表行,说完成。

Initially i tried just firing off the 1000 ajax requests inside the .each selector, but the browser was locking up. 最初,我尝试仅在.each选择器中触发1000个ajax请求,但浏览器已锁定。

So i changed it to try and use an internal ajax counter, so only ever fire off 50 at a time. 因此,我将其更改为尝试使用内部ajax计数器,因此一次只能触发50个。

Here's the code: 这是代码:

$('#do').click(function () {
    var maxAjaxRequests = 50;
    var ajaxRequests = 0;
    var doneCounter = 0;
    var toDo = $('#mytable tr').length;

    $.each($('#mytable > tr'), function (i, v) {
        while (doneCounter < toDo) {
            if (ajaxRequests <= maxAjaxRequests) {
                ajaxRequests++;
                doAsyncStuff($(this), function () {
                    ajaxRequests--;
                    doneCounter++;
                });
            } else {
                setTimeout(function() {
                }, 1000);
            }
        }
    });
});

function doAsyncStuff(tr, completeCallback) {   
    $.ajax({
        url: '/somewhere',
        type: 'POST',
        dataType: 'json',
        data: null,
        contentType: 'application/json; charset=utf-8',
        complete: function () {
            completeCallback();
        },
        success: function (json) {
            // update ui.
        },
        error: function (xmlHttpRequest, textStatus, errorThrown) {
            // update ui.
        }
    });
}

But the browser is still being locked up. 但是浏览器仍处于锁定状态。 It never goes into the $.ajax complete callback, even though i can see the request coming back successfully (via Fiddler). 即使我可以看到请求成功返回(通过Fiddler),也永远不会进入$.ajax完整回调。 Therefore its just sleeping, looping, sleeping, etc because the callback is never returned. 因此,它只是休眠,循环,休眠等,因为永远不会返回该回调。

I've got a feeling that the entire doAsyncStuff function needs to be asynchronous? 我感觉整个doAsyncStuff函数需要异步进行?

Any ideas on what i am doing wrong (or how i can do this better)? 关于我做错了什么的任何想法(或者我如何做得更好)?

You are doing a while loop inside the .each callback function, so there is much more ajax request than 1000, the worst is 1000*1000. 您正在.each回调函数中进行while循环,因此ajax请求的数量比1000多得多,最糟糕的是1000 * 1000。

You could delay each ajax request with different time. 您可以将每个ajax请求延迟不同的时间。

$('#do').click(function () {
    $('#mytable > tr').each(function (i, v) {
        var $this = $(this);
        setTimeout(function () {
            doAsyncStuff($this, function () {
               console.log('complete!');
            });
        }, i * 10);
    });
});

The browser gets locked because of the WHILE... You are creating an endless loop. 浏览器由于WHILE而被锁定...您正在创建一个无限循环。

The while loops runs over and over waiting for the doneCounter to be increased, but the javascript engine cannot execute the success call of the ajax since it is stuck in the while... while循环一遍又一遍地等待增加doneCounter,但是javascript引擎无法执行ajax的成功调用,因为它被卡在while中。

var callQueue = new Array();
$('#mytable > tr').each(function(key,elem){callQueue.push($(this));});

var asyncPageLoad = function(){
var tr = callQueue.splice(0,1);
$.ajax({
        url: '/somewhere',
        type: 'POST',
        dataType: 'json',
        data: null,
        contentType: 'application/json; charset=utf-8',
        complete: function () {
            completeCallback();
            asyncPageLoad();
        },
        success: function (json) {
            // update ui.
        },
        error: function (xmlHttpRequest, textStatus, errorThrown) {
            // update ui.
        }
    }
};
asyncPageLoad();

This will call the requests one by one. 这将一一调用请求。 If you want, simply do a for() loop inside to make maybe 5 calls? 如果您愿意,只需在内部进行for()循环以进行5个调用? And increase the amount if the browser is fine. 并增加数量,如果浏览器很好。

Actually, I prefer to send new request when current request is done. 实际上,我更喜欢在当前请求完成后发送新请求。 I used this method to dump db tables ( in this work ). 我使用了这种方法来转储数据库表( 在这项工作中 )。 Maybe it gives an idea. 也许它给出了一个主意。

See this link , check all check boxes and click Dump! 查看此链接 ,选中所有复选框,然后单击转储! button. 按钮。 And you can find the source codes here (see dumpAll function). 您可以在此处找到源代码(请参见dumpAll函数)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM