如何在不冻结网页的情况下同步调用Ajax

3
我有一些JavaScript代码,会触发大约100个对PHP脚本的调用。该PHP脚本会占用大量内存,并需要几秒钟才能完成,然后返回一个JSON响应(通过成功或失败来判断)。
我不希望使用异步方式进行AJAX调用,因为服务器会运行100个实例而陷入停滞,因此我尝试使用同步方式,但唯一的问题是它会在逐个调用脚本时冻结网页。
那么我该如何逐个触发AJAX调用,同时又不会冻结当前页面呢?
var a = [];
    a[0] = 'test';
    a[1] = 'hello';
    a[2] = 'another';

$(document).ready(function(){ 
  $.each(a, function(k,v) {
$.ajax({
  url:'/this-script-takes-a-few-seconds-to-complete.php',
  async:false,
  data: {foo: v},
  success: function(data){      
    console.log(data);  
  }
});
  });
});

15
你到底在做什么需要100次的AJAX请求? - Nick Craver
6个回答

15
你可以将它放在一个函数中,该函数执行下一个调用,并从你的success处理程序中调用它,如下所示:

你可以将其放入一个函数中,在函数内执行接下来的调用,然后从你的success处理程序中调用该函数,就像这样:

$(function(){ 
  var i = 0;
  function nextCall() {
    if(i == a.length) return; //last call was last item in the array
    $.ajax({
      url:'/this-script-takes-a-few-seconds-to-complete.php',
      data: { foo: a[i++] },
      success: function(data){      
        console.log(data);  
        nextCall();
      }
    });
  }
  nextCall();
});

虽然...更好的方式是不要进行100次调用,除非这是某种测试套件,否则我将重新审视整个方法。


2
注意:如果您从ajax回调的执行上下文中触发Ajax请求,IE6将会出现问题。将nextCall()调用包装在setTimeout()中以避免此问题(如果您的目标是IE6兼容性)。 - Roy Tinker
@Nick:我需要100+个调用。有什么建议的解决方案吗? - Uthistran Selvaraj.
这个东西救了我的命,但问题是我发现它太晚了。 - Mohsin Abbas

3
如果您不想让呼叫异步执行,那么浏览器就无法更新用户界面,从而导致冻结。为什么不能将其设置为异步执行呢?可以等待一个完成后再调用下一个,而不是一次性执行所有100个。

最好的方法是什么? - Paul
将 i 设为 0;然后使用 a[i] 作为参数调用函数,当函数完成(使用 success 函数)时,增加 i 并再次调用。当 i == a.length 时,你就完成了。 - Amir Raminfar

1

你需要对这个东西进行重构。100个ajax请求是疯狂的,而且它们全部都是同步的。

我建议你重构你的应用程序,这样你可以解析所有的数据并在一个异步过程中发送,或者用一些异步请求,而不是100个。

如果你需要100个,可以创建一个队列,并按顺序异步处理它们。


我假设他不能一次性完成所有调用,因为他想在每个请求之间更新UI。但如果他可以在一个请求中完成所有操作,那就很好。 - Amir Raminfar

0

编辑 - 正确答案

大多数浏览器会限制向单个服务器发送的HTTP请求数量,这样可以防止像您试图防止的那种情况发生(服务器超载)。我不确定现代浏览器的实际数字是多少,但我认为它比我在2005年Firefox中观察到的旧“2”要多。

一些资源:

旧答案

此脚本将每2秒调用同步的$.ajax,每次将数据从数组a中移出。UI仍然在每个请求实际执行时锁定,但允许在调用之间更新自身。我认为,这是完全同步和完全异步之间的一个很好的折衷。

请注意,此脚本具有破坏性 - a完成后将为空。如果您需要a的内容,则可能需要创建副本。

a = [
    'test',
    'hello',
    'another'
];

$(function() {
    var send = function() {
        $.ajax({
            url: '/this-script-takes-a-few-seconds-to-complete.php',
            async: false,
            data: {foo: a.shift()},
            success: function(data) {
                console.log(data)
            }
        });

        if (!a.length)
        {
            clearInterval(timer);
        }
    }

    var timer = setInterval(send, 2000);
});

0

问题在于Ajax的含义是“异步JavaScript和XML”...

试图同步执行Ajax会破坏使用Ajax的初衷。

尝试使用线程池并异步运行它。


-1

我曾遇到过类似问题,需要同步调用但IE会卡死。最终我采用了以下方法:

  1. 使用async:true代替同步调用。
  2. 在complete:function中递归调用下一个ajax请求。

这样可以异步地同步调用,使得我可以在前一个调用完成之后再进行后续的调用。


2
这个解决方案是在这个问题的被接受答案中提供的。请在提供自己的解决方案之前阅读现有的解决方案,这将使您避免重复,并为问题添加额外的信息。对于那些非常老的问题来说,这一点尤其重要,因为社区可能已经多次审查了问答,因此很少有什么可以改进的地方。哦,顺便说一下,欢迎来到StackOverflow! - bPratik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接