Я пытаюсь сделать страницу, которая будет генерировать набор результатов из сложного запроса к базе данных & PHP разбора … но это в основном не относится к делу … Главное, что это занимает минуту или две, и я надеюсь, что отображается индикатор выполнения, а не общая анимация GIF «загрузка …» картина.
Разрушение было бы …
Я знаю, как вернуть данные в запрос 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>
Отладка: вывод 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) также должен возвращать фиксированный размер фрагмента в первоначальном ответе, затем клиент отправляет TOTAL_COUNT / CHUNK_SIZE
запрашивает одновременно и объединяет ответы до последнего запроса. Так что это намного быстрее. Ты можешь использовать https://github.com/caolan/async в этом случае сделать код гораздо более читабельным.
Других решений пока нет …