Ajax на практике.

Progress Bar - индикатор процесса загрузки.

Серия статей "Ajax на практике"

В предыдущей статье, мы коснулись темы загрузки файлов методом $.ajax() и, если обычные данные грузятся и обрабатываются на сервере достаточно быстро, то с файлами этот процесс, может занять значительно больше времени, а тем более, если выполняется мультизагрузка. В первом случае, вполне достаточно вывести для пользователя какой-нибудь анимированный прелоадер, чтоб дать ему понять, что сервер не ушёл на обед, а занимается делом. Во втором же случае, гораздо разумней показать пользователю ход выполнения операции, т.к. веся́щий секунд 5 и больше прелоадер, может утомить юзера или, того хуже, если он подумает, что сервер завис, развернется и уйдет с вашего ресурса. Вот тут-то и пригодится нам "индикатор процесса", он же "прогресс-бар", он же "progress bar" и т.п. ;)

С частью html - всё достаточно просто, хотя и не так безоблачно. Для прогрессбара используют или тег <progress> (реже <meter>), или создают кастомный из любого понравившегося html-элемента. Первые два не очень кроссбраузерны, но предусмотренный в них альтернативный текст, который можно использовать для показа процентов выполнения загрузки, немного исправляет положение. Со вторым вариантом - приходится повозится в CSS, но это не проблема для людей знающих. Мы остановимся на первом, т.к. у нас сейчас основная цель - разобраться с механизмом на JavaScript.

Итак, создадим простую форму для загрузки файла и после поля файла, разместим прогресс-бар, в котором нас интересуют два атрибута: value - текущее значение и max - максимальное значение. Так как мы будем использовать проценты, значения будут колебатся от нуля до ста. Соответственно стартовое значение (value) должно быть "0", а максимальное (max) - "100" :

HTML (файл index.html)

<form action="handler.php" method="post" id="my_form" enctype="multipart/form-data">
  <p>
    <label for="my_file">Файл:</label>
      <input type="file" name="my_file" id="my_file">
        <progress id="progressbar" value="0" max="100"></progress>
  </p>
  <input type="submit" id="submit" value="Отправить">
</form>

В JS пишем практически всё, что разбирали в статье по "загрузке файлов", но добавляем параметр xhr, в callback-функции которого, мы можем работать с объектом XMLHttpRequest, изменяя или дополняя его поведение, получать доступ его свойствам и методам, устанавливать свои обработчики событий и т.д.:

jQuery (файл script.js)

$(function(){
  var progressBar = $('#progressbar');
  $('#my_form').on('submit', function(e){
    e.preventDefault();
    var $that = $(this),
        formData = new FormData($that.get(0));
    $.ajax({
      url: $that.attr('action'),
      type: $that.attr('method'),
      contentType: false,
      processData: false,
      data: formData,
      dataType: 'json',
      xhr: function(){
        var xhr = $.ajaxSettings.xhr(); // получаем объект XMLHttpRequest
        xhr.upload.addEventListener('progress', function(evt){ // добавляем обработчик события progress (onprogress)
          if(evt.lengthComputable) { // если известно количество байт
            // высчитываем процент загруженного
            var percentComplete = Math.ceil(evt.loaded / evt.total * 100);
            // устанавливаем значение в атрибут value тега <progress>
            // и это же значение альтернативным текстом для браузеров, не поддерживающих <progress>
            progressBar.val(percentComplete).text('Загружено ' + percentComplete + '%');
          }
        }, false);
        return xhr;
      },
      success: function(json){
        if(json){
      	  $that.after(json);
        }
      }
    });
  });
});

Что касается серверной части, то там работаем с файлом/файлами, как если бы вы их загружали обычным способом.
Готово! Теперь, чтобы протестировать на локальной машине, нужно выбрать файл побольше, иначе загрузка будет происходить практически моментально и работу прогрессбара, вы попросту не заметите. Что будет в обработчике в этом случае - не важно, главное, чтоб он был. И не забудьте перед тестированием, установить значение директивы upload_max_filesize чуть больше, чем загружаемый файл. Для времменого изменения - это проще всего сделать в файле .htaccess, прописав строку:

php_value upload_max_filesize 1000M # вместо 1000 - своё значение

P.S. На всякий случай, если кому-то понадобится сделать прогресс бар не на UPLOAD, а на DOWNLOAD то нужно внести маленькое изменение, а именно - установить соответствующий обработчик. Ну, естественно, что убрать лишнее. Такое может вам пригодиться, если, например, вы подгружаете на страницу большое изображение.

$(function(){
  var progressBar = $('#progressbar'),
      bigImg = '/image.png'; // путь к очень большой картинке
  // В примере - по клику на какой-то кнопке
  $('#get_big_file').on('click', function(e){
    e.preventDefault();
    $.ajax({
      url: bigImg,
      type: 'GET', // можно и POST
      contentType: false,
      processData: false,
      xhr: function(){
        var xhr = $.ajaxSettings.xhr();
        // Устанавливаем обработчик подгрузки
        xhr.addEventListener('progress', function(evt){
          if (evt.lengthComputable) {
            var percentComplete = Math.ceil(evt.loaded / evt.total * 100);
            progressBar.val(percentComplete);
          }
        }, false);
        return xhr;
      },
      success: function(json){
        // После того, как изображение полностью получено
        // подставляем его URL и выводим на экран
        if(json){
          $('#output').html('<img src="' + bigImg + '">');
        }
      }
    });
  });
});

Пробежавшись по всем четырем статьям, я надеюсь, что у вас уже не возникнет особых сложностей с тем, как работать с методом $.ajax() и вы без труда сможете внедрить его в свои проекты. И наконец, в завершение темы "Ajax", в следующей статейке, разберем реализацию ajax-запросов на чистом (нативном) JavaScript.

Incode Pro logo

57 комментариев

Страница 3 из 3  
Гость 06.09.2014 13:11
Респект только с последним не понял. Это типа когда не закачиваем файл а юзер скачивает у нас? Так а смысл если он и так видит процесс загрузки браузере? Или я чего не так понял? )) Все равно спасибо, полезно.
Гость 14.11.2014 21:08
отвечу гостю выше : когда загружается на сервер
Incode 07.01.2015 21:36
отвечу гостю выше : когда загружается на сервер
Насколько я понял, человек имел в виду не upload, а download и кое в чем он прав. Для отдачи файла пользователю на скачивание, этот код не имеет смысла, т.к. процесс загрузки отображает встроенный прогрессбар браузера. Но вот где он может пригодится (хоть и редко), так это в качестве прелоадера очень больших изображений. Я как-то не планировал делать демку по этому вопросу, но для лучше понимания, всё же решил наваять. В общем, смотрите по этой ссылке. Изображение, которое будет подгружаться, размером около 6Мб. Если скорость инета у вас не очень большая, то успеете заметить, как перед выводом изображения, прогрессбар показывает, какой объем файла подтянут с сервера клиенту.
Гость 07.03.2015 02:30
Добавил в закладки. Пригодится )
Гость 07.05.2015 13:22
Как принять файл на стороне сервера?
Incode 07.05.2015 16:47
Как принять файл на стороне сервера?
Точно так же, как и при обычной загрузке:
$_FILES['userfile'];
// где userfile - это имя поля файла (атрибут name)
Подробней читаем тут - Загрузка файлов методом POST
Гость 17.05.2015 19:02
Подскажите, как применить код "на DOWNLOAD" если я читаю данные с mySQL (80000 записей) ?. Получаю с Сервера массив. Процесс идет около 10 сек - без progressbar не обойтись.

function geting(DayOfWeek, NameMons, EpZoom) {
	            $.ajax({
                    url: 'data.php',
                    type: 'POST',
                    dataType: 'json',
                    data: {
                    jsonData: {DayOfWeek: DayOfWeek, NameMons: NameMons, EpZoom: EpZoom}
                    },
                    success: function (res) {
                        Hending_flow(res);
                    }
                });
            }
Страница 3 из 3  
Ваш комментарий:
X