Я пытаюсь создать страницу, которая будет генерировать результирующий набор из сложного запроса базы данных & php parsing ... но это в основном не относится к делу ... Главное, что это происходит минуту или две, чтобы закончить, и я надеюсь отобразить индикатор прогресса, а не общую анимацию gif анимации «loading ...».PHP/JS Progress Bar
Разбивка бы ...
- Пользователь открывает страницу A.
- Page запрашивает данные из страницы B (Скорее всего, AJAX).
- Страница B обрабатывает записи 100000+ или около того в базе данных и анализирует их.
- Страница A показывает индикатор выполнения, который показывает, насколько далеко проходит процесс
- Страница B возвращает набор результатов.
- Страница A отображает набор результатов.
Я знаю, как возвращать данные в запрос 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;
}
Monitor 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);
}
?>
EDIT: Я попробовал другой подход, где:
- Страница A AJAX вызывает страницу B, которая запускает запрос, и сохраняет прогресс переменной SESSION
- Страница AJAX вызывает страницу C каждые 2 секунды, которая просто возвращает значение переменной сеанса. Этот контур прекращается, когда он достигает 100
Однако это не совсем так. Кажется, что два запроса AJAX или две серверные серверы не работают одновременно.
Глядя на вывод отладки: оба вызова AJAX выполняются примерно в одно и то же время, но сценарий страницы B выполняется до завершения сам по себе, а затем запускается скрипт страницы C. Является ли это некоторым ограничением 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
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
Есть ряд подобных вопросов и ответов там ↑ → – Raad
Ни один из тех, на которых я смотрел, не ответил, что я был после (или, по крайней мере, они не казались). Например, многие из них касаются загрузки файлов, которые полагаются на загрузку файлов с помощью определенных переменных и функций. Я полагаю, что то, что я также прошу здесь, в дополнение к тому, как это сделать, заключается в следующем: возможно ли, чтобы сервер нажимал прогресс на пользователя, а затем пользователь должен был постоянно запрашивать его. (EG. SSE) – Kieran
Ах, хорошо - так что для «push» уведомлений (a la COMET) вы можете найти это полезным: http://stackoverflow.com/a/14436086/1407999 и этот http: //www.nolithius. com/game-development/comet-long-polling-with-php-and-jquery – Raad