Главная » Frontend » Значение поля total в событиях ProgressEvent. Особенности реализации прогрессбара с помощью ajax
2018/08/11Метки: , ,

Значение поля total в событиях ProgressEvent. Особенности реализации прогрессбара с помощью ajax

Появилась задача загружать ajax-ом с сервера файлы размером порядка нескольких десятков мегабайт. Чтобы пользователь знал, сколько ему придётся ещё ждать, было принято решение показывать пользователю не обычный лоадер-спиннер, а прогрессбар с процентом выполнения загрузки. Загружаемые файлы хорошо сжимаются gzip-ом, поэтому на сервере в конфиге nginx была включена соответствующая опция. Теперь эти большие файлы стали весить в 3-4 раза меньше, но всё равно занимали ощутимый объём.

Чтобы показывать реальный процент скаченных данных нужно знать общий объём и текущий скаченный объём: event.loaded / event.total. Количество скаченных байт можно получить прочитав свойство loaded объекта события ProgressEvent, а общий объём — свойство total. Однако при gzip-сжатии в заголовках ответа отсутствует поле lengthComputable, поскольку сжатие производится в режиме реального времени, т.е. данные начинают отдаваться до окончания полного сжатия файла.

Поэтому для организации прогрессбара требуется до старта загрузки с помощью ajax иметь информацию о размере скачиваемого файла, причём как в обычном виде, так и в gzip-е. Потому что, как оказалось, хотя данные и скачиваются в сжатом виде поле loaded даёт информацию о количестве скаченных байт в разархивированном виде. Так себя ведут почти все браузеры: Chrome, Opera, Edge. Лишь только Firefox показывает размер в сжатом виде. А если браузер и вовсе не поддерживает gzip, о чём сервер узнаёт по свойству Accept-Encoding заголовка запроса, то можно использовать свойство lengthComputable события ProgressEvent.

Для определения браузера можно использовать, например, библиотеку bowser.

function onProgress(event) {
	var total;
	if (event.lengthComputable) {
		// Размер файла берём из заголовка.
		total = event.total;
	} else {
		// Иначе размер файла берем из мета-данных в зависимости от типа сжатия.
		// Все браузеры кроме FF отдают в поле `loaded` количество байт до сжатия,
		// FF отдаёт количество байт, реально переданных по сети.
		if (event.target.getResponseHeader('Content-Encoding') === 'gzip' && bowser.firefox) {
			total = size_gzip;
		} else {
			total = size;
		}
	}
	if (!total || !event.loaded) return;
	console.log(event.loaded / total);
};

var size = 18874368;
var size_gzip = 4718592;
var request = new XMLHttpRequest();
request.upload.addEventListener("progress", onProgress, false);
Метки: Метки: , ,
Понравилась статья? — Ставь лайк!

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

×
Новости и обзор новинок рынка строительной техники.
Подпишитесь на обновления нашей группы!