XMLHttpRequest'ten ilerleme nasıl elde edilir


133

Bir XMLHttpRequest'in ilerlemesini almak mümkün mü (yüklenen bayt, indirilmiş bayt)?

Bu, kullanıcı büyük bir dosya yüklerken bir ilerleme çubuğu göstermek için yararlı olacaktır. Standart API bunu desteklemiyor gibi görünüyor, ancak belki de tarayıcıların herhangi birinde standart olmayan bir uzantı var mı? Sonuçta, müşteri kaç baytın yüklendiğini / indirildiğini bildiğinden, oldukça açık bir özellik gibi görünüyor.

Not: "İlerleme için sunucuyu yok et" alternatifinin farkındayım (şu anda yaptığım şey bu). bununla ilgili ana sorun (karmaşık sunucu tarafı kodu dışında), genellikle, büyük bir dosya yüklenirken, kullanıcının bağlantısının tamamen barındırılmasıdır, çünkü çoğu ISS yukarı akışsızdır. Bu yüzden ekstra istekte bulunmak umduğum kadar duyarlı değil. Tarayıcının her zaman sahip olduğu bu bilgiyi almanın bir yolu (belki de standart olmayan) olacağını umuyordum.

Yanıtlar:


137

Yüklenen baytlar için oldukça kolaydır. Sadece xhr.upload.onprogressetkinliği izleyin . Tarayıcı, yüklemek zorunda olduğu dosyaların boyutunu ve yüklenen verilerin boyutunu bilir, böylece ilerleme durumu bilgilerini sağlayabilir.

İndirilen baytlar için (bilgi alınırken xhr.responseText), biraz daha zordur, çünkü tarayıcı sunucu isteğinde kaç bayt gönderileceğini bilmiyor. Tarayıcının bu durumda bildiği tek şey, aldığı baytların boyutudur.

Bunun bir çözümü var, Content-Lengthtarayıcının alacağı baytların toplam boyutunu elde etmek için sunucu komut dosyasına bir başlık ayarlamak yeterlidir .

Daha fazla bilgi için https://developer.mozilla.org/en/Using_XMLHttpRequest adresine gidin .

Örnek: Sunucu komut dosyam bir zip dosyası okuyor (5 saniye sürüyor):

$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;

Toplam uzunluğu olduğunu biliyorum, çünkü şimdi sunucu komut dosyasının indirme işlemini izleyebilirsiniz:

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(); 
}

29
"İçerik Uzunluğu" tahmini bir uzunluk değil, tam uzunluk, çok kısa olmalı ve tarayıcı indirmeyi çok uzun süre kesecek ve tarayıcı indirme işleminin tamamlanamadığını varsayacaktır.
Chris Chilvers

@ChrisChilvers Bir PHP dosyasının doğru hesaplanamayacağı anlamına gelir, değil mi?
Hydroper

1
@nicematt bu örnekte bir dosyadan geldiği gibi iyi olurdu, ancak zip'i doğrudan bellekten aktarıyorsanız, bir içerik uzunluğu oluşturamaz veya tahmin edemezdiniz.
Chris Chilvers

3
@TheProHands Bir .php sayfasını ziyaret ettiğinizde, sunucu PHP dosyasını çalıştırır ve çıktısını size gönderir . Sunucunun çıktı uzunluğu .php dosyası değil gönderiliyor olmalıdır.
leewz

Birisi lütfen "$ ('# progressbar') satırının ne olduğunu açıklayabilir mi? Progressbar (" seçenek "," değer ", yüzdeKomplet);" anlamına geliyor? Bu belirli bir eklenti mi çağırıyor? Bu nasıl çalışıyor? Lütfen yanıtı yeni kullanıcılar için anlaşılır hale getirin.
Zac


8

En umut verici yaklaşımlardan biri, transferin ne kadarının tamamlandığını sormak için sunucuya geri ikinci bir iletişim kanalı açmak gibi görünüyor.


24
Sanırım bağlantı
Ronnie Royston


5

Yüklenen toplam için bunun üstesinden gelmenin bir yolu yok gibi görünüyor, ancak indirmek istediğiniz şeye benzer bir şey var. ReadyState 3 olduktan sonra, tüm içeriği kullanıma hazır olana kadar readyState 4'e geçene kadar, bir Dize olarak indirilen tüm içeriği (IE'de çalışmaz) almak için responseText öğesini düzenli olarak sorgulayabilirsiniz. Herhangi bir zamanda indirilen bayt, responseText içinde saklanan dizedeki toplam bayta eşit olacaktır.

Karşıya yükleme sorusuna ya hep ya hiç yaklaşımı için, yükleme için bir dize iletmeniz (ve bunun toplam baytını belirlemek mümkündür) çünkü readyState 0 ve 1 için gönderilen toplam bayt 0 ve readyState için toplam 2, geçirdiğiniz dizedeki toplam bayt sayısı olacaktır. ReadyState 3 ve 4'te gönderilen ve alınan toplam bayt, orijinal dizedeki baytların yanı sıra responseText içindeki toplam baytların toplamı olacaktır.


3

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

Sonuç


2

Apache kurulumunuza erişiminiz varsa ve üçüncü taraf koduna güveniyorsanız, apache yükleme ilerleme modülünü kullanabilirsiniz (apache kullanıyorsanız; ayrıca bir nginx yükleme ilerleme modülü de vardır ).

Aksi takdirde, dosyanın durumunu istemek için banttan vurabileceğiniz bir komut dosyası yazmanız gerekir (örneğin, tmp dosyasının dosya boyutunu kontrol edin).

Firefox 3'te devam eden bazı çalışmalar var Tarayıcıya yükleme ilerleme desteği eklemeye inanıyorum, ancak bu tüm tarayıcılara girmeyecek ve bir süre yaygın olarak kabul edilmeyecek (daha fazla yazık).


-7

Bunu saf javascript ile yapmanın tek yolu bir çeşit yoklama mekanizması uygulamaktır. Sunucu tarafından alınan bayt sayısını almak için sabit aralıklarla (örneğin her 5 saniyede bir) ajax istekleri göndermeniz gerekir.

Daha verimli bir yol flaş kullanmaktır. Flex bileşeni FileReference , önceden yüklenen bayt sayısını tutan periyodik olarak bir 'progress' olayı gönderir. Javascript ile yapışmanız gerekiyorsa, actionscript ve javascript arasında köprüler mevcuttur. İyi haber şu ki, bu iş zaten sizin için yapılmış :)

swfupload

Bu kütüphane, flash progress olayına bir javascript işleyici kaydedilmesini sağlar.

Bu çözüm, sunucu tarafında ek kaynaklar gerektirmemesi gibi hudge avantajına sahiptir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.