Как получить прогресс от XMLHttpRequest

Возможно ли получить прогресс XMLHttpRequest (загруженные байты, загруженные байты)?

Было бы полезно показать индикатор выполнения, когда пользователь загружает большой файл. Стандартный API, похоже, не поддерживает его, но может быть, есть какое-то нестандартное расширение в любом из браузеров? Похоже, что это довольно очевидная функция, поскольку клиент знает, сколько байтов было загружено/загружено.

Примечание. Я знаю, что альтернатива "опрос сервера для прогресса" (это то, что я делаю прямо сейчас). основная проблема с этим (кроме сложного кода на стороне сервера) заключается в том, что обычно при загрузке большого файла пользовательское соединение полностью закрывается, потому что большинство интернет-провайдеров предлагают плохой выход. Поэтому делать дополнительные запросы не так отзывчивы, как я надеялся. Я надеялся, что будет какой-то способ (может быть, нестандартный), чтобы получить эту информацию, которую браузер всегда имеет.

Ответ 1

Для загруженных байтов это довольно просто. Просто просмотрите событие xhr.upload.onprogress. Браузер знает размер файлов, которые он должен загрузить, и размер загруженных данных, поэтому он может предоставить информацию о ходе.

Для загруженных байтов (при получении информации с помощью xhr.responseText) это немного сложнее, потому что браузер не знает, сколько байтов будет отправлено в запросе сервера. Единственное, что браузер знает в этом случае, это размер байтов, которые он получает.

Существует решение для этого, достаточно установить заголовок Content-Length на сервере script, чтобы получить общий размер байтов, который будет получать браузер.

Для перехода к https://developer.mozilla.org/en/Using_XMLHttpRequest.

Пример: Мой сервер script читает zip файл (требуется 5 секунд):

$filesize=filesize('test.zip');

header("Content-Length: " . $filesize); // set header length
// if the headers is not set then the evt.loaded will be 0
readfile('test.zip');
exit 0;

Теперь я могу контролировать процесс загрузки сервера script, потому что я знаю его общую длину:

function updateProgress(evt) 
{
   if (evt.lengthComputable) 
   {  // evt.loaded the bytes the browser received
      // evt.total the total bytes set by the header
      // jQuery UI progress bar to show the progress on screen
     var percentComplete = (evt.loaded / evt.total) * 100;  
     $('#progressbar').progressbar( "option", "value", percentComplete );
   } 
}   
function sendreq(evt) 
{  
    var req = new XMLHttpRequest(); 
    $('#progressbar').progressbar();    
    req.onprogress = updateProgress;
    req.open('GET', 'test.php', true);  
    req.onreadystatechange = function (aEvt) {  
        if (req.readyState == 4) 
        {  
             //run any callback here
        }  
    };  
    req.send(); 
}

Ответ 2

Здесь приятно обсуждать индикатор прогресса для шаблона AJAX:

http://ajaxpatterns.org/Progress_Indicator

Один из наиболее перспективных подходов, по-видимому, открывает второй канал связи на сервере, чтобы спросить, какая часть передачи завершена.

Ответ 5

Для общего количества загруженных файлов, похоже, нет способа справиться с этим, но есть что-то похожее на то, что вы хотите загрузить. После того как ReadyState равно 3, вы можете периодически запрашивать responseText, чтобы получить все содержимое, загруженное до String (это не работает в IE), вплоть до того, как все это будет доступно, и в какой момент он перейдет на ReadyState 4. Итого байты, загруженные в любой момент времени, будут равны общим байтам в строке, сохраненной в responseText.

Для всего или ничего подходить к вопросу о загрузке, так как вам нужно передать строку для загрузки (и можно определить общие байты), то все байты, отправленные для readyState 0 и 1, будут равны 0, а total для readyState 2 будет общим байтом в строке, в которую вы проходили. Суммарное количество байтов, отправленных и полученных в readyState 3 и 4, будет суммой байтов в исходной строке плюс суммарные байты в responseText.

Ответ 6

Если у вас есть доступ к вашему программному обеспечению apache и доверенному стороннему коду, вы можете использовать модуль обновления загрузки apache (если вы используете apache, а также модуль обновления загрузки nginx).

В противном случае вам нужно написать script, чтобы вы могли ударить вне диапазона, чтобы запросить статус файла (например, проверка размера файла tmp).

В Firefox есть некоторая работа. Я полагаю, что добавить браузер для поддержки загрузки в браузере, но это не будет входить во все браузеры и быть широко принятым на некоторое время (более жалко).

Ответ 7

<!DOCTYPE html>
<html>
<body>
<p id="demo">result</p>
<button type="button" onclick="get_post_ajax();">Change Content</button>
<script type="text/javascript">
	function update_progress(e)
	{
	  if (e.lengthComputable)
	  {
	    var percentage = Math.round((e.loaded/e.total)*100);
	    console.log("percent " + percentage + '%' );
	  }
	  else 
	  {
	  	console.log("Unable to compute progress information since the total size is unknown");
	  }
	}
	function transfer_complete(e){console.log("The transfer is complete.");}
	function transfer_failed(e){console.log("An error occurred while transferring the file.");}
	function transfer_canceled(e){console.log("The transfer has been canceled by the user.");}
	function get_post_ajax()
	{
	  	var xhttp;
	  	if (window.XMLHttpRequest){xhttp = new XMLHttpRequest();}//code for modern browsers} 
	 	else{xhttp = new ActiveXObject("Microsoft.XMLHTTP");}// code for IE6, IE5	  	
	  	xhttp.onprogress = update_progress;
		xhttp.addEventListener("load", transfer_complete, false);
		xhttp.addEventListener("error", transfer_failed, false);
		xhttp.addEventListener("abort", transfer_canceled, false);	  	
	  	xhttp.onreadystatechange = function()
	  	{
	    	if (xhttp.readyState == 4 && xhttp.status == 200)
	    	{
	      		document.getElementById("demo").innerHTML = xhttp.responseText;
	    	}
	  	};
	  xhttp.open("GET", "http://it-tu.com/ajax_test.php", true);
	  xhttp.send();
	}
</script>
</body>
</html>

Ответ 8

Единственный способ сделать это с чистым javascript - это реализовать какой-то механизм опроса. Вам нужно будет отправлять запросы ajax с фиксированными интервалами (например, каждые 5 секунд), чтобы получить количество байтов, полученных сервером.

Более эффективным способом будет использование flash. Компонент flex FileReference периодически отправляет событие "progress", содержащее количество уже загруженных байтов. Если вам нужно придерживаться javascript, мосты доступны между actionscript и javascript. Хорошей новостью является то, что эта работа уже сделана для вас:)

swfupload

Эта библиотека позволяет зарегистрировать обработчик javascript в событии прогресса Flash.

Это решение обладает преимуществом, не требующим дополнительных ресурсов на стороне сервера.