是否可以同时从PHP服务器接收多个AJAX响应?

时间:2019-01-06 22:09:27

标签: javascript php jquery ajax progress-bar

我想在我的网站上创建一个进度条,该进度条跟踪PHP脚本的执行。

PHP脚本与Google API建立了许多连接,并将其接收的数据存储在数据库中。有时,此过程可能需要一分钟。

PHP脚本位于ajax/integrations-ajax.php文件中,并通过发送的GET AJAX请求启动,如果在网站上单击#link按钮。下面是该请求的jQuery代码:

$('#link').on('click', function () {
    var interval = setInterval(trackStatus, 1000);
    $.getJSON('ajax/integrations-ajax.php', {action: 'link'}).done(function (json) {            
        if (json.result == true) {
            showMessage('The account is successfully linked.', 'success');
        } else {
            showMessage('There is an error happened.', 'danger');
        }
    })
});

#link按钮还设置了每秒触发trackStatus功能的时间间隔:

function trackStatus() {
    $.getJSON('ajax/status-ajax.php', { 
        action: 'status'
    }).done(function (json) {
        console.log(json.status);
    });
}

如您所见,trackStatus函数将GET AJAX请求发送到ajax/status-ajax.php文件,并且应该每秒在浏览器控制台中显示状态。

为了在服务器上实现跟踪功能,我在ajax/integrations-ajax.php文件中制作了PHP脚本,以将状态存储在数据库中。您可以在下面看到其代码:

<?php
if(!is_ajax_request()) { exit; }
$action = isset($_GET['action']) ? (string) $_GET['action'] : '';
if ($action == 'link') {
    set_status_in_database(0);
    // some execution code;

    set_status_in_database(1);
    // some execution code;

    set_status_in_database(2);
    // some execution code;

    set_status_in_database(3);
    // some execution code;
    echo json_encode(['result' => true ]);
}

并创建了另一个PHP文件axax/status-ajax.php,该文件可以从数据库中恢复状态:

<?php
if(!is_ajax_request()) { exit; }
$action = isset($_GET['action']) ? (string) $_GET['action'] : '';
if ($action == 'status') {
    $return['result'] = get_status_from_database();
    echo json_encode($return);
}

但是请求似乎无法同时工作。直到未收到完成trackStatus脚本的响应,我才能收到ajax/integrations-ajax.php函数的响应。

我在浏览器中进行了性能分析,记录显示: enter image description here

那么,是否有可能同时执行请求?还是要实现跟踪功能,我需要重新考虑整个方法?

提前感谢您的帮助!


更新 谢谢大家的指教!特别是@Keith,因为他的解决方案最简单且有效。我在脚本的开头放置了session_write_close()函数,一切正常:

<?php
if(!is_ajax_request()) { exit; }
$action = isset($_GET['action']) ? (string) $_GET['action'] : '';
if ($action == 'link') {
    session_write_close();
    set_status_in_database(0);
    // some execution code;

    set_status_in_database(1);
    // some execution code;

    set_status_in_database(2);
    // some execution code;

    set_status_in_database(3);
    // some execution code;
    echo json_encode(['result' => true ]);
}

在这里您可以从浏览器中查看分析记录: enter image description here

4 个答案:

答案 0 :(得分:2)

建议您尝试使用EventSource。这是一个例子。

PHP

<?php
header('Content-Type: text/event-stream');
// recommended to prevent caching of event data.
header('Cache-Control: no-cache'); 

function send_message($id, $message, $progress) {
  $d = array('message' => $message , 'progress' => $progress);
  echo "id: $id" . PHP_EOL;
  echo "data: " . json_encode($d) . PHP_EOL;
  echo PHP_EOL;
  ob_flush();
  flush();
}

for($i=0; $i<4; $i++){
  set_status_in_database($i);
  // some execution code;
  send_message($i, "set status in database " . $i + 1 . " of 3' , $i*4);
  sleep(1);
}

send_message('CLOSE', 'Process complete');
?>

JavaScript

var es;

function startTask() {
  es = new eventSource('ajax/status-ajax.php');
  es.addEventListener('message', function(e) {
    var result = JSON.parse(e.data);
    console.log(result.message);
    if(e.lastEventId == 'CLOSE') {
      console.log('Received CLOSE closing');
      es.close();
      showMessage('The account is successfully linked.', 'success');
    } else {
      $('.progress').css("width", result.progress + '%');
    }
  });
  es.addEventListener('error', function(e) {
    console.log('Error occurred', e);
    es.close();
  });
}

function stopTask() {
  es.close();
  console.log('Interrupted');
}

$('#link').on('click', function(e) {
  e.preventDefault();
  startTask($(this));
});

参考:

希望对您有用。

答案 1 :(得分:2)

虽然PHP可以毫无问题地处理并发请求,但确实要序列化的一个区域是Session,基本上,在请求期间,PHP会为该用户在SESSION上设置排他锁。 IOW:当此锁打开时,来自同一用户的其他请求将不得不等待。通常这不是问题,但是如果您的请求运行时间较长,它将阻止其他请求,例如AJax请求等。

默认情况下,PHP将在写入会话数据,然后结束请求。但是,如果您确定不再需要写入任何会话数据,则调用session_write_close将更早地释放锁。

更多信息在这里-> http://php.net/manual/en/function.session-write-close.php

答案 2 :(得分:1)

php逻辑和JavaScript语法似乎都不错;但是,以最少的php代码示例为例,假定它的资源过多。 MySQL可能很忙,这就是获取状态可能等待MySQL的原因。

我通过将更新状态 写入文件而不是争用数据库资源来解决这个问题。

答案 3 :(得分:0)

由于您考虑使用其他方法,因此让我推荐GraphQL作为数据库上的薄层/ api。

那里有很多Php解决方案,例如Siler。寻找一个具有subscriptions的功能(并非所有功能都可以),因为这是您要寻找的功能。订阅用于创建网络套接字(您的PHP和Javascript之间的流),从而将与状态相关的所有通信减少到一个呼叫。

是的,这可能是“向大炮射击”,但也许您还有其他东西在飞来飞去,那么也许值得考虑。 fantastic document有一个有趣的概念。您将可以在resolver functions中重用大多数与数据库相关的Php。