Как получить прогресс от XMLHttpRequest - PullRequest
130 голосов
/ 17 сентября 2008

Можно ли получить ход выполнения запроса XMLHttpRequest (загружено байт, загружено байт)?

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

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

Ответы [ 8 ]

132 голосов
/ 12 сентября 2010

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

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

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

Для получения дополнительной информации перейдите к https://developer.mozilla.org/en/Using_XMLHttpRequest.

Пример: Мой серверный скрипт читает 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;

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

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(); 
}
9 голосов
/ 29 июля 2010
9 голосов
/ 17 сентября 2008

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

http://ajaxpatterns.org/Progress_Indicator

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

7 голосов
5 голосов
/ 17 сентября 2008

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

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

3 голосов
/ 29 января 2016

<!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>

Result

2 голосов
/ 17 сентября 2008

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

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

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

0 голосов
/ 17 сентября 2008

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

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

SWFUpload

Эта библиотека позволяет зарегистрировать обработчик javascript для события прогресса флэш-памяти.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...