【问题标题】:Prevent AJAX Queue from blocking browser防止 AJAX 队列阻塞浏览器
【发布时间】:2012-08-28 06:47:50
【问题描述】:

注意:简化示例..

我有一个包含 1000 个表格行的页面。对于每一行,我需要通过 AJAX 调用在服务器上“做一些工作”,然后在回调中更新该表行,说完成。

最初我尝试在 .each 选择器中触发 1000 个 ajax 请求,但浏览器被锁定。

所以我将其更改为尝试使用内部 ajax 计数器,因此一次只能触发 50 个。

代码如下:

$('#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.
        }
    });
}

但是浏览器仍然被锁定。它永远不会进入$.ajax 完成回调,即使我可以看到请求成功返回(通过 Fiddler)。因此它只是休眠、循环、休眠等,因为回调永远不会返回。

感觉整个doAsyncStuff函数需要异步?

对我做错了什么有什么想法(或者我怎样才能做得更好)?

【问题讨论】:

  • 如果您批量发送请求,这可能会更高效。通过单个/更少的 HTTP 请求。
  • @Mythril - 不能那样做。每个操作都需要独立。 “为什么”不在这个问题的范围内。
  • 没有很多好的理由这样做......所以我仍然很好奇为什么......但也许你可以使用 html webworker?
  • 我真的不敢相信您需要为每一行触发一个 ajax 请求 - 特别是在同时触发它们时,这表明它们可以捆绑在一起。你真的应该多想你在做什么。尽管如此,为您的 ajax 调用使用 webworker 将是一件好事。但是,您不能为此使用 jQuery,而必须使用本机 xmlhttp。

标签: javascript jquery ajax


【解决方案1】:

你在.each回调函数里面做了一个while循环,所以ajax请求比1000多很多,最坏的是1000*1000。

您可以用不同的时间延迟每个 ajax 请求。

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

【讨论】:

    【解决方案2】:

    浏览器由于 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();
    

    这将一一调用请求。如果您愿意,只需在内部执行一个 for() 循环即可进行 5 次调用?并且如果浏览器没问题就增加数量。

    【讨论】:

    • 请注意,这部分代码产生了一个奇怪的错误,我在 IE7 和 8 中尝试追踪了 3 天。POST 数据未随请求一起发送,尽管服务器响应几毫秒,浏览器在继续之前等待正好 60 秒。在不同的调用中随机发生。
    【解决方案3】:

    实际上,我更喜欢在当前请求完成后发送新请求。我使用这种方法转储数据库表(in this work)。也许它给出了一个想法。

    查看this link,选中所有复选框并单击转储!按钮。并且你可以找到源代码here(见dumpAll函数)。

    【讨论】:

      猜你喜欢
      • 2015-05-14
      • 2022-01-05
      • 2014-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-28
      • 2012-04-16
      • 2013-07-03
      相关资源
      最近更新 更多