两个同时的 AJAX 请求无法并行运行

12

我有两个同时运行的AJAX请求问题。我有一个将数据导出到XSLX的PHP脚本。这个操作需要很长时间,所以我尝试向用户显示进度。我正在使用AJAX和数据库方法。实际上,我非常确定它曾经可以工作,但我无法弄清楚为什么,在任何浏览器中都不再起作用了。新浏览器有什么变化吗?

$(document).ready(function() {

        $("#progressbar").progressbar();

        $.ajax({
            type: "POST",
            url: "{$BASE_URL}/export/project/ajaxExport",
            data: "type={$type}&progressUid={$progressUid}" // unique ID I'm using to track progress from database
        }).done(function(data) {
            $("#progressbar-box").hide();
            clearInterval(progressInterval);
        });

        progressInterval = setInterval(function() {
            $.ajax({
                type: "POST",
                url: "{$BASE_URL}/ajax/progressShow",
                data: "statusId={$progressUid}" // the same uinque ID
            }).done(function(data) {
                data = jQuery.parseJSON(data);
                $("#progressbar").progressbar({ value: parseInt(data.progress) });
                if (data.title) { $("#progressbar-title").text(data.title); }
            });
        }, 500);

    });
  • 进度在数据库中正确更新
  • JS 计时器试图获取进度,我可以在控制台看到它,但所有这些请求都要加载第一个脚本的整个持续时间,一旦脚本结束,这些 AJAX 进度调用就会被加载

那么,为什么第二个 AJAX 调用要等待第一个调用完成呢?


3
一些PHP Web服务器配置只允许每个会话同时运行一个连接。因此,如果您正在使用会话,请在一个页面上进行实验:(a)开始一个会话,然后(b)休眠60秒。然后尝试在同一个浏览器中加载多个此页面的实例-它们可能会依次加载。 - halfer
你最近更新了jQuery版本吗? - Joshua - Pendo
1
此外,一般来说,多个 AJAX 操作不是最佳实践,因为它会浪费过多的时间在额外的 HTTP 调用上。你能否将它们合并为一个操作,并在 JSON 字符串中返回多个结果呢? - halfer
3
如果您正在使用服务器端会话,在请求活动期间,PHP默认会锁定会话文件,这意味着您不能在任何时间有多个未完成的请求处于活动状态。 - Marc B
Marc B,你说得对!这是会话问题。我之前使用的是CodeIgniter会话库,但最近我改用了本地会话库,我没有意识到这可能是问题所在。谢谢您。您可以将其发布为答案,以便我将其标记为已接受。 - filip.karas
使用jQuery并行运行多个AJAX请求 - srikanth_yarram
6个回答

40

听起来像是会话阻塞的问题。

默认情况下,PHP将其会话数据写入文件。当您使用session_start()启动会话时,它会打开文件进行写操作,并锁定文件以防止并发编辑。这意味着对于通过使用会话的PHP脚本传递的每个请求,都必须等待第一个会话完成文件操作。

解决此问题的方法是更改PHP会话以不使用文件或关闭会话写入,如下所示:

<?php
    session_start(); // starting the session

    $_SESSION['foo'] = 'bar'; // Write data to the session if you want to

    session_write_close(); // close the session file and release the lock

    echo $_SESSION['foo']; // You can still read from the session.

哎呀卡朗巴。不是PHP会话的粉丝,但使用Symfony进行开发时会大量使用它们。这很有道理,但我从来没有想到过。好帮手! - eggmatters

3
经过一番折腾,我找到了另一个导致这些非并行的 AJAX 请求发生的方法,与 PHP 会话处理完全无关...因此,我在此将其发布出来,以便任何遇到同样问题的人可以通过 Google 找到它。
XDebug 可能会导致此问题,我不会感到意外如果 Zend Debugger 也会有类似问题。
在我的情况下,我安装了:
- XDebug 在我的本地 LAMP 堆栈上 - 启用了 xdebug.remote_autostart - 我的 IDE 接受入站调试器连接,即使没有活动断点
这导致我的所有 AJAX 测试都按顺序运行,无论如何。回顾起来,强制顺序处理是很有意义的(从调试事物的角度看),但我只是没有注意到我的 IDE 仍在幕后交互。
告诉 IDE 完全停止监听后,平行运行恢复正常,我成功重现了我一直在寻找的竞态条件。

2

请注意,如果您启用了输出缓冲(在PHP 7+中是默认的),那么session_write_close()(chrislondon的答案)可能无法解决问题。您需要在php.ini中设置output_buffering = Off,否则会导致会话未能正确关闭。


0

a.php生成一个主HTML页面,其中包含对b.phpc.php的两个同时进行的AJAX调用。为了让b.phpc.php共享会话变量,会话变量必须在第一个AJAX调用之前存在。如果这是正确的,a.phpb.php可以更改会话变量的值并查看彼此的值。因此,在生成HTML页面时,请使用a.php创建会话变量。至少,这是Rogers共享Web Hosting的工作方式。


0
在使用API时,有时需要向不同的端点发出多个AJAX请求。您可以通过使用jQuery的$.when()函数并行请求数据来加快速度,而不是等待一个请求完成后再发出下一个请求:

同时运行多个AJAX请求


-1

你也可以设置

async: true,

这是为 ExtJs 设计的吗? - Sangoku

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