【问题标题】:$.ajax inside $.each blocking browser$.each 中的 $.ajax 阻塞浏览器
【发布时间】:2015-05-14 21:59:35
【问题描述】:

我有这样的事情:遍历 id 并为每个 ID 向服务器(相同域)发出 ajax 请求 (async:true) 并将接收到的数据附加到 DOM 元素。完成这项任务并不难,它确实有效。示例代码:

$.each(ids, function (index, id) {
    $.ajax({
        type: 'POST',
        url: "http://localhost/example/"+id,
        success: function (data) {
            $('#content').append(data);
        }
    });
});

我的问题是:当我需要循环遍历多个 ID(例如 1000 个)时,它会发送大量 ajax,并且浏览器“冻结”,当我单击链接时,它会等待所有 ajax 请求完成,然后是打开点击的链接。

超时不是一个选项,因为我需要显示尽可能多的接收数据。如果需要 1 秒或 100 秒完成,这没有问题,因为用户会看到其他已完成的请求

那么,处理这个问题的最佳方法是什么?单击链接时停止 ajax 请求,例如 this ?或者有更好的方法来做到这一点

【问题讨论】:

  • 如果您可能远程发送接近 1000 个 ajax 请求的任何地方,那么问题不在于浏览器冻结,而在于您的应用程序的架构非常糟糕。找到更好的方法。
  • 我会说:构建一个 ID 列表并将整个列表一次性发送到服务器。
  • 进一步的仅供参考 - 浏览器只能处理 6 个模拟最大连接。如果它接收到更多,它会将它们排队并按顺序处理它们(当一个连接完成时,它将打开一个新的,最多同时连接 6 个)。这就是为什么在运行数百个连接时无法从链接加载响应的原因 - 浏览器必须等到打开/排队的连接不超过 5 个,才能打开一个新的(第 6 个)加载您刚刚单击的链接的内容。
  • 浏览器会限制打开请求的数量。例如,我相信 Firefox 只会做 6 个。因此,如果有一千个请求,您的请求将需要很长时间。您应该分批进行追加。一次发送 20 个或更多 ID。然后它看起来仍然是动态的,但不会阻塞作品。
  • 正如前两位评论者所指出的,您从错误的方式处理问题。无需发送 1000 个单独的 AJAX 请求,您可以将您的 ID 作为数组提交,并允许服务器完成繁重的工作。再说一次,这真的取决于你对这 1000 个请求究竟做了什么。它们是简单的还是复杂的?您是否正在查询数据库?如果是,数据库是否被适当索引?

标签: javascript jquery ajax each


【解决方案1】:

您可以让服务器返回格式为 json 的 json,而不是对应用程序进行 1000 次 ajax 调用

[{ id: 0, content: "A",
id: 1, content: "B",
.
.
id: n, content: "Nth content" }]

有类似的请求

var idList = [];
$.each(ids, function(index, id) {
    idList.push(id);
});
$.ajax({
type: "POST",
data: { id: idList },
success: function(data) {
    $.each(data, function(index, v) {
        $("#content").append(v.content);
    })
}).error(function(response) {
    $("#content").append(response);
});

据我所知,Chrome 一次可以处理 8 个并发 ajax 请求,像 1000 这样的数字对它来说太多了。上面的代码会将 ajax 调用的数量从 1000 减少到 1。

但是,如果您确实想拨打 1000 次这样的电话,那么您最好这样做

var idList = [];
$.each(ids, function(index, id) {
    idList.push(id);
});
function makeAjax() {
    $.ajax({
        type: "POST"
        data: { id : idList.pop()},
        success: function(data) {
            $("#content").append(data);
        }
    }).done(function() {
        if(idList.length>0) {
            makeAjax();
        }
    });
}

下面的代码一次最多产生 8 个 ajax 调用。

var idList = [];
$.each(ids, function(index, id) {
    idList.push(id);
});
var MAX_THREADS = 8;
var CURRENT_THREADS = 0;

function makeAjax() {
    CURRENT_THREADS++;
    $.ajax({
        type: "POST"
        data: { id : idList.pop()},
        success: function(data) {
            $("#content").append(data);
        }
    }).done(function() {
        CURRENT_THREADS--;
    });
}

function callAjax() {
    if(CURRENT_THREADS < MAX_THREADS) {
        makeAjax();
    }
    if(idList.length > 0) {
        setTimeout(callAjax, 1000);
    }
}

callAjax();

但是我不建议这样做。如果一次获取所有 id 的内容需要很长时间,则最好使用分页等其他解决方案。

【讨论】:

  • 这是完美的解决方案!但是,如果我在一个 ajax 请求中发送所有 ID,用户将需要等待服务器处理所有 ID 以显示一些内容。当服务器完成处理 ID 时,我需要显示内容。这就是为什么我不能一起发送所有 ID。
  • 更新了答案,这一次发送一个 id,将更新为同时发送更多。
  • 男人!这就是我要找的!我想这会像一个魅力!谢谢!! :D
【解决方案2】:

更好的方法是改变您请求数据的方式。

如果可能,请尝试将服务器更改为接受多个 ID,并一次使用所有 ID 发出一个请求。这样,您就可以循环访问数据而不是 AJAX 请求。

考虑一下。对于一个包含 1000 个 ID 的数组,每次您点击该函数时,您都会发出至少 1001 个请求(页面有 1 个请求!)。如果该请求由数据库支持,则有 1000 次单独的数据库命中。

现代网络浏览器只能处理这么多同时发生的 AJAX 请求,然后将其余请求排队等待稍后处理。在您提供的代码中可能没有提高性能的好方法。

【讨论】:

  • 但是,如果我通过ajax发送整个ID数组,我无法一一显示结果。这个想法也是尽快显示与 ID 相关的一些信息,同时处理其他信息。
  • 您需要使用 $.each 遍历结果集(如 Prathik 的示例)。也许您还有一些未包含的代码?但是对于一个简单的 $("#content").append(data) 来说,应该没那么难。
  • 当没有缓存响应时,每个 ajax 需要 1~2 秒。 1000(可能更多)需要很长时间才能等待响应。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-17
  • 1970-01-01
  • 2017-08-04
  • 1970-01-01
相关资源
最近更新 更多