# XMLHttpRequest: индикация прогресса Запрос `XMLHttpRequest` состоит из двух фаз:
  1. Стадия закачки (upload). На ней данные загружаются на сервер. Эта фаза может быть долгой для POST-запросов.
  2. Стадия скачивания (download). После того, как данные загружены, браузер скачивает ответ с сервера. Если он большой, то это может занять существенное время.
Для каждой стадии предусмотрены события, "рассказывающие" о процессе выполнения. [cut] ## XMLHttpRequestUpload Для отслеживания прогресса на стадии закачки существует объект [XMLHttpRequestUpload](https://xhr.spec.whatwg.org/#xmlhttprequesteventtarget), доступный как `xhr.upload`. У него нет методов, он предназначен исключительно для обработки событий при закачке. Вот их полный список: Пример установки обработчиков на стадию закачки: ```js xhr.upload.onprogress = function(event) { alert('Загружено на сервер ' + event.loaded + ' байт из '+ event.total); } xhr.upload.onload = function() { alert('Данные полностью загружены на сервер!'); } xhr.upload.onerror = function() { alert('Произошла ошибка при загрузке данных на сервер!'); } ``` После того, как загрузка завершена, будет начато скачивание ответа. На этой фазе `xhr.upload` уже не нужен, а в дело вступают обработчики событий на самом объекте `xhr`, в частности `xhr.onprogress`: ```js xhr.onprogress = function(event) { alert('Получено с сервера ' + event.loaded + ' байт из '+ event.total); } ``` Все события, возникающие в этих обработчиках, имеют тип [ProgressEvent](https://xhr.spec.whatwg.org/#progressevent), то есть имеют свойства `loaded` -- количество уже пересланных данных в байтах и `total` -- общее количество данных. ## Загрузка файла с индикатором прогресса Современный `XMLHttpRequest` позволяет отправить на сервер всё, что угодно. Текст, файл, форму. Мы, для примера, рассмотрим загрузку файла с индикацией прогресса. Это требует от браузера поддержки [File API](http://www.w3.org/TR/FileAPI/), то есть исключает IE9-. File API позволяет получить доступ к содержимому файла, который перенесён в браузер при помощи Drag'n'Drop или выбран в поле формы. Форма для выбора файла с обработчиком `submit`: ```html
``` Здесь мы почти не пользуемся File API. Его роль -- получить файл из формы через свойство `files` элемента `` и далее мы сразу передадим его `xhr.send` в функции `upload`: ```js function upload(file) { var xhr = new XMLHttpRequest(); // обработчики можно объединить в один, // если status == 200, то это успех, иначе ошибка xhr.onload = xhr.onerror = function() { if(this.status == 200) { log("success"); } else { log("error " + this.status); } }; // обработчик для закачки xhr.upload.onprogress = function(event) { log(event.loaded + ' / '+ event.total); } xhr.open("POST", "upload", true); xhr.send(file); } ``` Полный пример, основанный на коде выше: [codetabs src="progress"] ## Событие onprogress в деталях Событие `onprogress` имеет одинаковый вид при закачке на сервер (`xhr.upload.onprogress`) и при получении ответа (`xhr.onprogress`). Оно получает объект `event` типа [ProgressEvent](https://xhr.spec.whatwg.org/#progressevent) со свойствами:
`loaded`
Сколько байт уже переслано. Имеется в виду только тело запроса, заголовки не учитываются.
`lengthComputable`
Если `true`, то известно полное количество байт для пересылки, и оно хранится в свойстве `total`.
`total`
Общее количество байт для пересылки, если известно. При HTTP-запросах оно передаётся в заголовке `Content-Length`.
Ещё особенности, которые необходимо учитывать при использовании `onprogress`: ## Файлы и формы Выше мы использовали `xhr.send(file)` для посылки файл пересылается в теле запроса. При этом посылается только содержимое файла. Если нужно дополнительно передать имя файла или что-то ещё -- это можно удобно сделать через форму, при помощи объекта [FormData](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/FormData/Using_FormData_Objects): Создадим форму `formData` и прибавим к ней поле с файлом `file` и именем `"myfile"`: ```js var formData = new FormData(); formData.append("myfile", file); xhr.send(formData); ``` Данные будут отправлены в кодировке `multipart/form-data`. Серверный фреймворк обработает это как обычную форму.