it-swarm.it

Come ottenere progressi da XMLHttpRequest

È possibile ottenere lo stato di avanzamento di un XMLHttpRequest (byte caricati, byte scaricati)?

Ciò sarebbe utile per mostrare una barra di avanzamento quando l'utente sta caricando un file di grandi dimensioni. L'API standard non sembra supportarla, ma forse c'è qualche estensione non standard in nessuno dei browser là fuori? Dopotutto sembra una funzionalità abbastanza ovvia, poiché il client sa quanti byte sono stati caricati/scaricati.

nota: sono a conoscenza dell'alternativa "polling server for progress" (è quello che sto facendo in questo momento). il problema principale con questo (a parte il complicato codice lato server) è che in genere, durante il caricamento di un file di grandi dimensioni, la connessione dell'utente viene completamente nascosta, poiché la maggior parte degli ISP offre scarsi upstream. Quindi fare richieste extra non è così reattivo come speravo. Speravo che ci fosse un modo (forse non standard) per ottenere queste informazioni, che il browser ha sempre.

130
Pete

Per i byte caricati è abbastanza semplice. Ti basta monitorare il xhr.upload.onprogress evento. Il browser conosce la dimensione dei file che deve caricare e la dimensione dei dati caricati, quindi può fornire le informazioni sullo stato di avanzamento.

Per i byte scaricati (quando si ottengono le informazioni con xhr.responseText), è un po 'più difficile, perché il browser non sa quanti byte verranno inviati nella richiesta del server. L'unica cosa che il browser conosce in questo caso è la dimensione dei byte che sta ricevendo.

C'è una soluzione per questo, è sufficiente impostare un Content-Length header sullo script del server, al fine di ottenere la dimensione totale dei byte che il browser riceverà.

Per ulteriori informazioni, visitare https://developer.mozilla.org/en/Using_XMLHttpRequest .

Esempio: lo script del mio server legge un file Zip (richiede 5 secondi):

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

Ora posso monitorare il processo di download dello script del server, perché so che è la lunghezza totale:

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(); 
}
134
albanx
9
Markus Peröbner

C'è una bella discussione sull'indicatore di progresso per AJAX qui:

http://ajaxpatterns.org/Progress_Indicator

Uno degli approcci più promettenti sembra riaprire un secondo canale di comunicazione al server per chiedergli quanto del trasferimento è stato completato.

8
Sean McMains
7

Per il totale caricato non sembra esserci un modo per gestirlo, ma c'è qualcosa di simile a quello che vuoi scaricare. Una volta che readyState è 3, è possibile eseguire periodicamente una query di responseText per ottenere tutto il contenuto scaricato fino a una stringa (non funziona in IE), fino a quando non è disponibile tutto, a quel punto passerà a readyState 4. Il totale i byte scaricati in qualsiasi momento saranno uguali ai byte totali nella stringa memorizzata in responseText.

Per un approccio tutto o niente alla domanda di caricamento, poiché è necessario passare una stringa per il caricamento (ed è possibile determinarne i byte totali), il totale dei byte inviati per readyState 0 e 1 sarà 0 e il totale per readyState 2 saranno i byte totali nella stringa che hai passato. I byte totali inviati e ricevuti in readyState 3 e 4 saranno la somma dei byte nella stringa originale più i byte totali in responseText.

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

3
Forums Lover

Se hai accesso all'installazione di Apache e ti fidi del codice di terze parti, puoi utilizzare modulo di avanzamento caricamento Apache (se usi Apache; esiste anche un modulo di avanzamento caricamento nginx ).

Altrimenti, dovresti scrivere uno script che puoi colpire fuori banda per richiedere lo stato del file (controllando ad esempio la dimensione del file tmp).

Ci sono alcuni lavori in corso su Firefox 3, credo che aggiungerò il supporto all'avanzamento del caricamento nel browser, ma questo non entrerà in tutti i browser e sarà ampiamente adottato per un po '(più è un peccato).

2
Aeon