Cara mendapatkan kemajuan dari XMLHttpRequest

133

Apakah mungkin untuk mendapatkan kemajuan XMLHttpRequest (byte diunggah, byte diunduh)?

Ini akan berguna untuk menampilkan bilah kemajuan saat pengguna mengunggah file besar. API standar tampaknya tidak mendukungnya, tapi mungkin ada beberapa ekstensi non-standar di salah satu browser di luar sana? Sepertinya fitur yang cukup jelas untuk dimiliki, karena klien tahu berapa banyak byte yang diunggah / diunduh.

Catatan: Saya mengetahui alternatif "polling server untuk kemajuan" (inilah yang saya lakukan sekarang). masalah utama dengan ini (selain kode sisi server yang rumit) adalah bahwa biasanya, saat mengunggah file besar, koneksi pengguna sepenuhnya disiram, karena sebagian besar ISP menawarkan hulu yang buruk. Jadi membuat permintaan tambahan tidak responsif seperti yang saya harapkan. Saya berharap akan ada cara (mungkin tidak standar) untuk mendapatkan informasi ini, yang dimiliki browser setiap saat.

Pete
sumber

Jawaban:

137

Untuk byte yang diunggah itu cukup mudah. Pantau saja xhr.upload.onprogressacara tersebut. Peramban mengetahui ukuran file yang harus diunggah dan ukuran data yang diunggah, sehingga dapat memberikan informasi kemajuan.

Untuk byte yang diunduh (saat menerima info xhr.responseText), itu sedikit lebih sulit, karena browser tidak tahu berapa byte yang akan dikirim dalam permintaan server. Satu-satunya hal yang diketahui browser dalam hal ini adalah ukuran byte yang diterimanya.

Ada solusi untuk ini, cukup dengan mengatur Content-Lengthheader pada skrip server, untuk mendapatkan ukuran total byte yang akan diterima browser.

Untuk lebih lanjut, kunjungi https://developer.mozilla.org/en/Using_XMLHttpRequest .

Contoh: Skrip server saya membaca file zip (butuh 5 detik):

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

Sekarang saya dapat memantau proses pengunduhan skrip server, karena saya tahu panjang totalnya:

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(); 
}
albanx
sumber
29
Perlu dicatat, "Panjang Konten" bukan panjang perkiraan, itu harus panjang yang tepat, terlalu pendek dan browser akan memotong unduhan, terlalu lama dan browser akan menganggap unduhan gagal untuk menyelesaikan.
Chris Chilvers
@ChrisChilvers Itu berarti file PHP mungkin tidak dihitung dengan benar, kan?
Hydroper
1
@nicematt dalam contoh itu akan baik-baik saja karena berasal dari file, tetapi jika Anda streaming zip langsung dari memori Anda tidak bisa hanya membuat panjang konten atau memperkirakannya.
Chris Chilvers
3
@TheProHands Ketika Anda mengunjungi halaman .php, server menjalankan file PHP dan mengirimkan hasilnya kepada Anda . Server harus mengirim panjang output, bukan file .php.
leewz
Dapatkah seseorang tolong jelaskan apa baris "$ ('# progressbar'). Progressbar (" option "," value ", persenComplete);" cara? Apakah ini menggunakan plugin tertentu? Bagaimana cara kerjanya? Harap jadikan jawaban ini dapat dimengerti oleh pengguna baru.
Zac
8

Salah satu pendekatan yang paling menjanjikan tampaknya membuka saluran komunikasi kedua kembali ke server untuk menanyakan berapa banyak transfer telah selesai.

Sean McMains
sumber
24
Saya pikir tautannya mungkin mati
Ronnie Royston
5

Untuk total yang diunggah tampaknya tidak ada cara untuk mengatasinya, tetapi ada sesuatu yang mirip dengan yang Anda inginkan untuk diunduh. Setelah readyState adalah 3, Anda dapat secara berkala meminta responseText untuk mendapatkan semua konten yang diunduh sejauh String (ini tidak berfungsi di IE), hingga semuanya tersedia pada titik mana ia akan beralih ke readyState 4. Total byte yang diunduh pada waktu tertentu akan sama dengan total byte dalam string yang disimpan di responseText.

Untuk pendekatan semua atau tidak sama sekali terhadap pertanyaan unggahan, karena Anda harus memberikan string untuk unggah (dan dimungkinkan untuk menentukan total byte itu) total byte yang dikirim ke readyState 0 dan 1 akan menjadi 0, dan total untuk readyState 2 akan menjadi total byte dalam string yang Anda masukkan. Total byte yang dikirim dan diterima di readyState 3 dan 4 akan menjadi jumlah byte dalam string asli ditambah total byte dalam responseText.

Orclev
sumber
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>

Hasil

Forum Lover
sumber
2

Jika Anda memiliki akses ke instalasi apache dan mempercayai kode pihak ketiga, Anda dapat menggunakan modul progres unggah apache (jika Anda menggunakan apache; ada juga modul progres unggah nginx ).

Jika tidak, Anda harus menulis skrip yang dapat Anda tekan keluar dari band untuk meminta status file (misalnya memeriksa ukuran file dari file tmp).

Ada beberapa pekerjaan yang sedang berlangsung di firefox 3 Saya percaya untuk menambahkan dukungan kemajuan unggah ke browser, tapi itu tidak akan masuk ke semua browser dan diadopsi secara luas untuk sementara waktu (lebih disayangkan).

Aeon
sumber
-7

Satu-satunya cara untuk melakukannya dengan javascript murni adalah dengan menerapkan semacam mekanisme polling. Anda harus mengirim permintaan ajax pada interval tetap (misalnya masing-masing 5 detik) untuk mendapatkan jumlah byte yang diterima oleh server.

Cara yang lebih efisien adalah dengan menggunakan flash. FileReference komponen fleksibel mengirimkan secara berkala peristiwa 'progres' yang menahan jumlah byte yang sudah diunggah. Jika Anda harus tetap menggunakan javascript, jembatan tersedia antara skrip tindakan dan javascript. Berita baiknya adalah pekerjaan ini telah dilakukan untuk Anda :)

swfupload

Pustaka ini memungkinkan untuk mendaftarkan penangan javascript pada acara kemajuan flash.

Solusi ini memiliki keuntungan besar karena tidak memerlukan sumber daya tambahan di sisi server.

Alexandre Victoor
sumber