我正在尝试制作一个页面,该页面将通过复杂的数据库查询和php解析生成结果集...但这主要是要点...要点是,这需要一两分钟才能完成,并且我希望显示一个进度条,而不是普通的gif动画“正在加载...”图片。
故障将是...
我知道如何将数据返回给ajax查询,但是我的问题是我不知道如何连续返回数据以显示进程的状态(例如,扫描的行数百分比)。
我已经研究了EventSource/Server-Sent-Events,它显示了 promise ,我只是不太确定如何使其正常工作,或者是否有更好的方法来做到这一点。
我尝试制作一个快速的小模型页面,仅使用EventSource可以正常工作,但是当我将其拆分为一个eventSource调用(该页面监视 session 变量的更改)和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>
Java脚本
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>
调试: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
最佳答案
在类似的情况下,我通常是这样进行的:
重要:成功后,客户端再次发送相同的请求。
OK, THERE ARE 54555 RECORDS.
。我使用此计数来启动进度栏。 THAT'S ALL
,客户端将呈现数据。 我认为,您已经明白了。
注意:您可以并行请求所有块,但这是一种复杂的方法。服务器(页面B)还应在初始响应中返回固定的chunksize,然后客户端同时发送
TOTAL_COUNT / CHUNK_SIZE
请求并合并响应,直到最后一个请求完成为止。因此它要快得多。在这种情况下,可以使用https://github.com/caolan/async使代码更具可读性。