it-swarm-es.tech

Cómo progresar desde XMLHttpRequest

¿Es posible obtener el progreso de un XMLHttpRequest (bytes cargados, bytes descargados)?

Esto sería útil para mostrar una barra de progreso cuando el usuario está cargando un archivo grande. La API estándar no parece admitirlo, pero ¿quizás haya alguna extensión no estándar en alguno de los navegadores? Parece ser una característica bastante obvia, después de todo, ya que el cliente sabe cuántos bytes se cargaron o descargaron.

nota: Soy consciente de la alternativa de "sondear el servidor para ver el progreso" (es lo que estoy haciendo en este momento). El principal problema con esto (aparte del complicado código del lado del servidor) es que, normalmente, al cargar un archivo grande, la conexión del usuario está completamente suspendida, porque la mayoría de los ISP ofrecen un flujo ascendente pobre. Por lo tanto, hacer solicitudes adicionales no es tan receptivo como esperaba. Esperaba que hubiera una forma (tal vez no estándar) de obtener esta información, que el navegador tiene en todo momento.

130
Pete

Para los bytes subidos es bastante fácil. Simplemente supervise el evento xhr.upload.onprogress. El navegador conoce el tamaño de los archivos que tiene que cargar y el tamaño de los datos cargados, por lo que puede proporcionar la información de progreso.

Para los bytes descargados (cuando se obtiene la información con xhr.responseText), es un poco más difícil, porque el navegador no sabe cuántos bytes se enviarán en la solicitud del servidor. Lo único que el navegador sabe en este caso es el tamaño de los bytes que está recibiendo.

Hay una solución para esto, es suficiente establecer un encabezado Content-Length en el script del servidor, para obtener el tamaño total de los bytes que va a recibir el navegador.

Para más información, vaya a https://developer.mozilla.org/en/Using_XMLHttpRequest .

Ejemplo: la secuencia de comandos de mi servidor lee un archivo Zip (tarda 5 segundos):

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

Ahora puedo monitorear el proceso de descarga del script del servidor, porque sé que es la longitud total:

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

Aquí hay una buena discusión sobre el indicador de progreso para el patrón AJAX:

http://ajaxpatterns.org/Progress_Indicator

Uno de los enfoques más prometedores parece ser abrir un segundo canal de comunicación de vuelta al servidor para preguntarle cuánto de la transferencia se ha completado.

9
Sean McMains
9
Markus Peröbner
7
Maciej Łebkowski

Para el total cargado no parece haber una manera de manejar eso, pero hay algo similar a lo que quieres descargar. Una vez que readyState sea 3, puede consultar periódicamente responseText para obtener todo el contenido descargado hasta el momento como una Cadena (esto no funciona en IE), hasta que esté disponible en todo momento, y en ese momento pasará a readyState 4. Los bytes descargados en cualquier momento dado serán iguales al total de bytes en la cadena almacenada en responseText.

Para un enfoque de todo o nada a la pregunta de carga, ya que tiene que pasar una cadena para cargar (y es posible determinar el total de bytes), el total de bytes enviados para readyState 0 y 1 será 0, y el total para readyState 2 será el total de bytes en la cadena que pasó. El total de bytes enviados y recibidos en readyState 3 y 4 será la suma de los bytes en la cadena original más el total de bytes en 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

Si tiene acceso a su instalación de Apache y confía en el código de terceros, puede usar el módulo de progreso de carga de Apache (si usa Apache; también hay un módulo de progreso de carga de nginx ).

De lo contrario, tendría que escribir un script que se puede salir de la banda para solicitar el estado del archivo (por ejemplo, verificando el tamaño del archivo tmp).

Creo que se está trabajando en Firefox 3 para agregar soporte de progreso de carga al navegador, pero eso no va a entrar en todos los navegadores y será ampliamente adoptado por un tiempo (más es una pena).

2
Aeon