JavaScript — индикатор выполнения PHP / JS

Я пытаюсь сделать страницу, которая будет генерировать набор результатов из сложного запроса к базе данных & PHP разбора … но это в основном не относится к делу … Главное, что это занимает минуту или две, и я надеюсь, что отображается индикатор выполнения, а не общая анимация GIF «загрузка …» картина.

Разрушение было бы …

  • Пользователь открывает страницу А.
  • Страница A запрашивает данные со страницы 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;
}

Монитор 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);
}
?>

РЕДАКТИРОВАТЬ:
Я пробовал другой подход, где:

  • Страница A AJAX вызывает страницу B, которая выполняет запрос и сохраняет ход выполнения в переменную SESSION.
  • Страница A AJAX вызывает страницу C каждые 2 секунды, что просто возвращает значение переменной сеанса. Этот цикл завершается, когда он достигает 100

Однако это тоже не совсем работает. Похоже, что два 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

7

Решение

В подобных случаях я обычно делаю это так:

  • Клиент отправляет запрос AJAX на страницу B.
    Важный: В случае успеха клиент снова отправляет тот же запрос.
  • По первому запросу на странице B говорится: OK, THERE ARE 54555 RECORDS., Я использую этот счетчик для запуска индикатора выполнения.
  • При каждом следующем запросе страница B возвращает порцию данных. Клиент считает размер чанка и обновляет индикатор выполнения. Также он собирает куски в один список.
  • На последнем запросе, когда все данные отправлены, страница B говорит: THAT'S ALL и клиент предоставляет данные.

Я думаю, вы поняли идею.

ПРИМЕЧАНИЕ: вы можете запросить все куски параллельно, но это сложный способ. Сервер (страница B) также должен возвращать фиксированный размер фрагмента в первоначальном ответе, затем клиент отправляет TOTAL_COUNT / CHUNK_SIZE запрашивает одновременно и объединяет ответы до последнего запроса. Так что это намного быстрее. Ты можешь использовать https://github.com/caolan/async в этом случае сделать код гораздо более читабельным.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]