[英]Is there a possibility to receive several AJAX responses from PHP server simultaneously?
I want to make a progress bar on my website, which tracks execution of a PHP script. 我想在我的网站上创建一个进度条,该进度条跟踪PHP脚本的执行。
The PHP script makes a bunch of connections with Google API and stores the data it receives in the database. PHP脚本与Google API建立了许多连接,并将其接收的数据存储在数据库中。 Sometimes the process can take a minute.
有时,此过程可能需要一分钟。
The PHP script is located in ajax/integrations-ajax.php
file and launched by GET AJAX request sent, if on the website to click #link
button. 该PHP脚本位于
ajax/integrations-ajax.php
文件中,并通过GET AJAX请求发送启动,如果在网站上单击#link
按钮。 Below is jQuery code for the request: 以下是该请求的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');
}
})
});
This #link
button, also sets interval which fires trackStatus
function each second: 此
#link
按钮还设置间隔,该间隔会trackStatus
触发trackStatus
函数:
function trackStatus() {
$.getJSON('ajax/status-ajax.php', {
action: 'status'
}).done(function (json) {
console.log(json.status);
});
}
As you can see, trackStatus
function sends GET AJAX requests to ajax/status-ajax.php
file and should show status in browser console every second. 如您所见,
trackStatus
函数将GET AJAX请求发送到ajax/status-ajax.php
文件,并且应该每秒在浏览器控制台中显示状态。
To implement tracking ability on the server I made the PHP script in ajax/integrations-ajax.php
file to store status in the database. 为了在服务器上实现跟踪功能,我在
ajax/integrations-ajax.php
文件中制作了PHP脚本,以将状态存储在数据库中。 Its code you can see below: 您可以在下面看到其代码:
<?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 ]);
}
And created another PHP file axax/status-ajax.php
which can recover the status from the database: 并创建了另一个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);
}
But the requests appear not to be working simultaneously. 但是这些请求似乎无法同时工作。 I can't receive responses for
trackStatus
function until the response on completion ajax/integrations-ajax.php
script isn't received. 在收到关于完成
ajax/integrations-ajax.php
脚本的响应之前,我无法收到trackStatus
函数的响应。
I made a profiling record in browser, which show that: 我在浏览器中进行了性能分析,记录显示:
So, is there a possibility to execute requests simultaneously? 那么,是否有可能同时执行请求? Or to implement the tracking ability I need to rethink the whole approach?
还是要实现跟踪功能,我需要重新考虑整个方法?
Thanks in advance for help! 在此先感谢您的帮助!
Update Thank you all for your advice! 更新谢谢大家的建议! And especially to @Keith, because his solution is the easiest and works.
特别是@Keith,因为他的解决方案最简单且有效。 I have put session_write_close() function in the beginning for the script and everything works:
我在脚本的开头放置了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 ]);
}
Here you can see profiling record from a browser: 在这里,您可以查看来自浏览器的分析记录:
Would advise trying EventSource . 建议尝试使用EventSource 。 Here is an example.
这是一个例子。
PHP 的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 的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));
});
Reference: 参考:
Hope that is useful for you. 希望对您有用。
While PHP can handle concurrent requests without issue, one area that does get serialized is the Session, basically PHP during a request will place an exclusive lock on the SESSION, for that user. 虽然PHP可以毫无问题地处理并发请求,但确实可以序列化的一个区域是Session,基本上,在请求期间,PHP会为该用户在SESSION上设置排他锁。 IOW: While this lock is on, other requests from the same user will have to wait.
IOW:当此锁打开时,来自同一用户的其他请求将不得不等待。 This is normally not an issue, but if you have long running requests it will block other requests, like AJax requests etc.
通常这不是问题,但是如果您有长时间运行的请求,它将阻止其他请求,例如AJax请求等。
As a default PHP will write session data at then end off the request,. 默认情况下,PHP将在写入会话数据,然后结束请求。 But if you are sure you no longer need to write any session data, calling
session_write_close
will release the lock much sooner. 但是,如果您确定不再需要写入任何会话数据,则调用
session_write_close
将更快地释放该锁。
More info here -> http://php.net/manual/en/function.session-write-close.php 更多信息在这里-> http://php.net/manual/en/function.session-write-close.php
Both php logic and JavaScript syntax seem to be fine; php逻辑和JavaScript语法似乎都不错; however, with the minimal amount of php code example it is assumed that it's resource heavy.
但是,以最少的php代码示例为例,它假定资源很繁重。 MySQL might be busy, which is why get status may wait for MySQL.
MySQL可能很忙,这就是为什么获取状态可能要等待MySQL。
I have gone around such a problem by making the update status written to a file instead of competing for database resources. 通过将更新状态 写入文件而不是争用数据库资源,我解决了这个问题。
Since you consider using a different approach, let me recommend GraphQL as a thin layer / api above your database. 由于您考虑使用其他方法,因此让我推荐GraphQL作为数据库之上的薄层/ api。
There are quite a few Php-solutions out there, for example Siler . 那里有很多Php解决方案,例如Siler 。 Look for one that has subscriptions (not all do), as this would be the feature you are looking for.
寻找一个有订阅 (不是全部)的人,因为这是您要寻找的功能。 Subscriptions are used to create a websocket (stream between your Php and Javascript), reducing all status-related communication to one call.
订阅用于创建Websocket(Php和Javascript之间的流),从而将与状态相关的所有通信减少到一个呼叫。
Yes, this may be "shooting cannons at birds", but maybe you have other things flying around, then it might be worth considering. 是的,这可能是“向大炮射击”,但也许您还有其他东西在飞来飞去,那么也许值得考虑。 There is a fantastic document to familiarize with the intriguing concept.
有一个很棒的文档可以熟悉这个有趣的概念。 You'd be able to reuse most of your database-related Php within the resolver functions .
您将能够在resolver函数内重用大多数与数据库相关的Php。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.