我正在尝试创建一个页面,该页面将从复杂的数据库查询生成结果集。 php解析......但这主要是在这一点上......重点是这需要一两分钟才能完成,我希望显示一个进度条,而不是一个通用的gif动画“loading ...”图片。
细分将是......
我知道如何将数据返回到ajax查询,但我的问题是我不知道如何连续返回数据以显示进程的状态(例如扫描的行数百分比)。
我查看了EventSource / Server-Sent-Events,它显示了承诺,我不太确定如何使其正常工作,或者是否有更好的方法。
我试过制作一个快速的小模型页面,只使用EventSource工作正常,但当我将其拆分为eventSource调用(监视会话变量以进行更改的页面)和ajax请求(实际数据发送/返回)它崩溃了。
我可能错过了一些明显的东西,或做了一些愚蠢的错误,但这是我所拥有的大部分内容......任何帮助,建议,提示,甚至完全其他方法的建议都会很棒: )
用户页面:
<!DOCTYPE html>
<html>
<head>
<title>Dynamic Progress Bar Example</title>
<script src="script.js"></script>
</head>
<body>
<input type="button" value="Submit" onclick="connect()" />
<progress id='progressor' value="0" max='100' style=""></progress>
</body>
</html>
的Javascript
var es;
function connect() {
startListener();
$.ajax({
url: "server.php",
success: function() {
alert("Success");
},
error: function() {
alert("Error");
}
});
}
function startListener() {
es = new EventSource('monitor.php');
//a message is received
es.addEventListener('message', function(e) {
var result = JSON.parse(e.data);
if (e.lastEventId == 'CLOSE') {
alert("Finished!");
es.close();
} else {
var pBar = document.getElementById('progressor');
pBar.value = result;
}
});
es.addEventListener('error', function(e) {
alert('Error occurred');
es.close();
});
}
function stopListener() {
es.close();
alert('Interrupted');
}
function addLog(message) {
var r = document.getElementById('results');
r.innerHTML += message + '<br>';
r.scrollTop = r.scrollHeight;
}
监控PHP
<?php
SESSION_START();
header('Content-Type: text/event-stream');
// recommended to prevent caching of event data.
header('Cache-Control: no-cache');
function send_message($id, $data) {
$d = $data;
if (!is_array($d)){
$d = array($d);
}
echo "id: $id" . PHP_EOL;
echo "data: " . json_encode($d) . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
$run = true;
$time = time();
$last = -10;
while($run){
// Timeout kill checks
if (time()-$time > 360){
file_put_contents("test.txt", "DEBUG: Timeout Kill", FILE_APPEND);
$run = false;
}
// Only update if it's changed
if ($last != $_SESSION['progress']['percent']){
file_put_contents("test.txt", "DEBUG: Changed", FILE_APPEND);
$p = $_SESSION['progress']['percent'];
send_message(1, $p);
$last = $p;
}
sleep(2);
}
?>
编辑: 我尝试了一种不同的方法,其中:
然而,这也不是很有效。似乎两个AJAX请求或服务器端的两个脚本没有同时运行。
查看调试输出:两个AJAX调用几乎同时执行,但随后页面B脚本自行运行完成,然后 - 然后 - 页面C脚本运行。这是PHP的一些限制我错过了吗?
更多代码!
服务器(页面B)PHP
<?PHP
SESSION_START();
file_put_contents("log.log", "Job Started\n", FILE_APPEND);
$job = isset($_POST['job']) ? $_POST['job'] : 'err_unknown';
$_SESSION['progress']['job'] = $job;
$_SESSION['progress']['percent'] = 0;
$max = 10;
for ($i=0; $i<=$max;$i++){
$_SESSION['progress']['percent'] = floor(($i/$max)*100);
file_put_contents("log.log", "Progress now at " . floor(($i/$max)*100) . "\n", FILE_APPEND);
sleep(2);
}
file_put_contents("log.log", "Job Finished", FILE_APPEND);
echo json_encode("Success. We are done.");
?>
进展(第C页)PHP
<?php
SESSION_START();
file_put_contents("log.log", "PR: Request Made", FILE_APPEND);
if (isset($_SESSION['progress'])){
echo json_encode(array("job"=>$_SESSION['progress']['job'],"progress"=>$_SESSION['progress']['percent']));
} else {
echo json_encode(array("job"=>"","progress"=>"error"));
}
?>
索引(页面A)JS / HTML
<!DOCTYPE html>
<html>
<head>
<title>Progress Bar Test</title>
</head>
<body>
<input type="button" value="Start Process" onclick="start('test', 'pg');"/><br />
<progress id="pg" max="100" value="0"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script type="text/javascript">
var progress = 0;
var job = "";
function start(jobName, barName){
startProgress(jobName, barName);
getData(jobName);
}
function getData(jobName){
console.log("Process Started");
$.ajax({
url: "server.php",
data: {job: jobName},
method: "POST",
cache: false,
dataType: "JSON",
timeout: 300,
success: function(data){
console.log("SUCCESS: " + data)
alert(data);
},
error: function(xhr,status,err){
console.log("ERROR: " + err);
alert("ERROR");
}
});
}
function startProgress(jobName, barName){
console.log("PG Process Started");
progressLoop(jobName, barName);
}
function progressLoop(jobName, barName){
console.log("Progress Called");
$.ajax({
url: "progress.php",
cache: false,
dataType: "JSON",
success: function(data){
console.log("pSUCCESS: " . data);
document.getElementById(barName).value = data.progress;
if (data.progress < 100 && !isNaN(data.progress)){
setTimeout(progressLoop(jobName, barName), (1000*2));
}
},
error: function(xhr,status,err){
console.log("pERROR: " + err);
alert("PROGRESS ERROR");
}
});
}
</script>
</body>
</html>
Debug:log.log输出
PR: Request Made
Job Started
Progress now at 0
Progress now at 10
Progress now at 20
Progress now at 30
Progress now at 40
Progress now at 50
Progress now at 60
Progress now at 70
Progress now at 80
Progress now at 90
Progress now at 100
Job Finished
PR: Request Made
答案 0 :(得分:2)
在类似的情况下,我通常这样做:
OK, THERE ARE 54555 RECORDS.
。我使用此计数来启动进度条。THAT'S ALL
并且客户端呈现数据。我想,你已经有了这个主意。
注意:您可以并行请求所有块,但这是一种复杂的方式。服务器(页面B)还应在初始响应中返回固定的chunksize,然后客户端同时发送TOTAL_COUNT / CHUNK_SIZE
个请求并组合响应直到最后一个请求完成。所以它要快得多。在这种情况下,您可以使用https://github.com/caolan/async来使代码更具可读性。