К основному контенту

AJAX и прогресс выполнения (progressbar)

Коротко о насущном: есть задача, отображать прогресс выполнения PHP скрипта на странице сайта. Тема достаточно интересная, с учетом того, что в основном своем при переходе или при обновлении элемента люди обновляют страницу. Конечно, это совсем не удобно, и да - это решается при помощи AJAX. Глядя со стороны все тривиально: первый AJAX запрос запускает скрипт, а второй запрашивает статус прогресса. Естественно, этот статус нужно где-то хранить. И первое, что приходит на ум - сессии. Уверен, что все движки на PHP их используют, а если это не движок, тогда тоже не страшно, их можно включить функцией session_start.

Вот на этом месте я бы, на месте читателя, задался вопросом: "Если все так просто, зачем писать статью?". Да, вопрос вполне корректный. Но статья ради одной изюминки, за которую мне пришлось немного побороться.

Все дело в сессиях! 

Когда я написал 3 скрипта (тестовый скрипт PHP, который создавал видимость загрузки; PHP скрипт, который возвращал прогресс выполнения; HTML страница с двумя JavaScript функциями, которые отправляли AJAX запрос на оба эти скрипта), то увидел, что "все плохо" - оба запроса отправляются и я получаю результат, но не сам процесс. Другими словами, при нажатии кнопки, стартующей скрипт с эмуляцией загрузки мне ничего не говорил, а скрипт, который запрашивал прогресс возвращал только конечный результат в 100%. Конечно, это не то, чего мне хотелось.

Затянул с развязкой! 

Итак, дело в сессиях! Когда запускался скрипт с эмуляцией, он стартовал сессию и записывал в нее статус прогресса. Поскольку он использует цикл в своей основе, то и запись значения в сессию производилась на каждой итерации. Сессия стартовала, в нее производится запись, но мы стартуем второй скрипт, который считывает данные из сессии. И вот она кульминация, второй скрипт не может считать данные из сессии, поскольку первый скрипт продолжает в нее писать. Решение есть! В этом нам поможет другой оператор session_write_close. Он не закрывает, не останавливает и не убивает сессию, он просто говорит, что сессия закрыта на запись и можно ее читать.

Много слов, а где же практика?

Ниже я привожу все 3 скрипта, которые работают.

test_sleep.php
/**
 * Цикл для эмуляции загрузки
 */
for ($i = 1; $i <= 10; $i++)
{
    /**
     * Стартуем сессию
     */
    session_start();
 
    /**
     * Записываем значение прогресса в переменную сессии
     */
    $_SESSION['ls_sleep_test'] = $i * 10;
 
    /**
     * Закрываем сессию на запись
     */
    session_write_close();
 
    /**
     * Ждем 1 секунду
     */
    sleep(1);
}
 
/**
 * Выходим из скрипта
 */
exit();

test_progress.php
/**
 * Стартуем сессию
 */
session_start();
 
/**
 * Выводим значение прогресса
 */
echo isset($_SESSION['ls_sleep_test']) ? $_SESSION['ls_sleep_test'] : '';
 
/**
 * Выходим из скрипта
 */
exit();

index.html
<script type="text/javascript">
function ls_ajax_test() {
        /**
         * Переменная интервала.
         * Будем запускать функцию опроса результата прогресса каждую секунду
         * @type object
         */
        var myVar = setInterval(function() {
            ls_ajax_progress();
        }, 1000);
 
        /**
         * Выполняем AJAX запрос к скрипту эмуляции
         */
        $.ajax({
            type: 'POST',
            url: '/services/test_sleep.php',
            success: function(data) {
                /**
                 * По завершению работы скрипта эмуляции останавливаем таймер 
                 * опроса прогресса
                 * @returns {Boolean}
                 */
                clearInterval(myVar);
 
                /**
                 * В результирующий тег пишем результат
                 * @returns {Boolean}
                 */
                $('#progress').html('DONE');
            },
        });
 
        /**
         * На всякий случай вернем FALSE
         * @returns {Boolean}
         */
        return false;
    }
    function ls_ajax_progress() {
        /**
         * Выполняем AJAX запрос к скрипту опроса результата прогресса
         * @returns {Boolean}
         */
        $.ajax({
            type: 'POST',
            url: '/services/test_progress.php',
            success: function(data) {
                /**
                 * В реультирующий тег пишем то, что вернул скрипт
                 */
                $('#progress').html(data);
            },
        });
 
        /**
         * На всякий случай вернем FALSE
         * @returns {Boolean}
         */
        return false;
    }
</script>   <!--Кнопочка старта--> <input type="button" class="btn btn-primary" value="START" onclick="return ls_ajax_test(); return false;" /> <div id="progress"> <!--Результат прогресса--> Progress </div>

Комментарии

Отправить комментарий

Популярные сообщения из этого блога

Прямые ссылки на файлы Google диска

В предыдущей статье я рассказал, как подключить свой JavaScript файл к блогу BLOGSPOT . Но для того, что бы их подключить нужны прямые ссылки на файл, а Google диск при предоставлении общего доступа к файлу выдает ссылку на предварительный просмотр, которая никак напрямую не ссылается на файл. Для Google диска прямая ссылка на файл - это ссылка на скачивание. Ниже описаны два способа создания ссылки на скачивание на примере файла prism.js.

События для ведения таблиц

Как и всегда, в пылу проекта внезапно родилась Z табличка. Главный нюанс был в том, что она должна была хранить пароли для авторизации на стороннем сервере. Естественно, никто не хотел хранить пароли в открытом виде, а двустороннее шифрование SAP не умеет без сторонних пакетов и надстроек. Далее, все как обычно - придумали алгоритм, сделали табличку. Дело осталось за малым - нужно шифровать пароли, которые вводит пользователь. Делать отдельную программу нет смысла, поскольку ее функционал мало чем будет отличаться от сгенерированного. Вот здесь на помощь приходят события! С их помощью можно, наверное, все. По крайней мере, я не нашел чего-либо, что нельзя сделать с данными через события.

OOP ALV GRID с HTML шапкой

В этой статье хочу постараться подробно описать и привести пример, как можно создать ALV отчет с таблицей на весь экран и с HTML шапкой вверху. Я не буду описывать начальный этап, где пишется селекционный экран или делается выборка данных. Будем считать, что основа у нас есть и нам нужно просто вывести данные. Главной изюминкой является то, что нужно вывести ALV GRID на экран без использования каких-либо дополнительных элементов на экране. Step-By-Step Шаг 1. Создание окна Создаем самое простое окно с номером 100. На него не нужно кидать никаких контейнеров. Оно нам нужно только для модулей PAI и PBO и вывода на него ALV GRID.