it-swarm-pt.tech

Como obter progresso de XMLHttpRequest

É possível obter o progresso de um XMLHttpRequest (bytes carregados, bytes baixados)?

Isso seria útil para mostrar uma barra de progresso quando o usuário estiver carregando um arquivo grande. A API padrão não parece oferecer suporte, mas talvez haja alguma extensão não padrão em qualquer um dos navegadores existentes? Parece um recurso bastante óbvio, afinal, já que o cliente sabe quantos bytes foram carregados/baixados.

note: Estou ciente da alternativa "pesquisar o servidor em busca de progresso" (é o que estou fazendo agora). O principal problema com isso (além do complicado código do lado do servidor) é que, normalmente, ao fazer o upload de um arquivo grande, a conexão do usuário é completamente fechada, porque a maioria dos ISPs oferece upstream ruim. Então, fazer solicitações extras não é tão responsivo quanto eu esperava. Eu estava esperando que houvesse uma maneira (talvez não padrão) de obter essa informação, que o navegador tem em todos os momentos.

130
Pete

Para os bytes enviados, é muito fácil. Apenas monitore o evento xhr.upload.onprogress. O navegador sabe o tamanho dos arquivos que ele deve enviar e o tamanho dos dados enviados, para que ele possa fornecer as informações de progresso.

Para os bytes baixados (ao obter a informação com xhr.responseText), é um pouco mais difícil, porque o navegador não sabe quantos bytes serão enviados na requisição do servidor. A única coisa que o navegador sabe nesse caso é o tamanho dos bytes que está recebendo.

Existe uma solução para isso, basta configurar um cabeçalho Content-Length no script do servidor, para obter o tamanho total dos bytes que o navegador receberá.

Para mais, acesse https://developer.mozilla.org/en/Using_XMLHttpRequest .

Exemplo: Meu script de servidor lê um arquivo Zip (leva 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;

Agora eu posso monitorar o processo de download do script do servidor, porque eu sei que é o comprimento 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(); 
}
133
albanx

Há uma boa discussão sobre o padrão de progresso para o padrãoAJAX aqui:

http://ajaxpatterns.org/Progress_Indicator

Uma das abordagens mais promissoras parece estar abrindo um segundo canal de comunicação de volta ao servidor para perguntar quanto da transferência foi concluída.

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

Para o upload total, parece não haver uma maneira de lidar com isso, mas há algo parecido com o que você deseja fazer o download. Uma vez que o readyState é 3, você pode consultar periodicamente o responseText para obter todo o conteúdo baixado até uma String (isso não funciona no IE), até que tudo esteja disponível e em que ponto ele fará a transição para o readyState 4. O total Os bytes baixados a qualquer momento serão iguais ao total de bytes da string armazenada em responseText.

Para uma abordagem de tudo ou nada à pergunta de upload, já que você precisa passar uma string para upload (e é possível determinar o total de bytes dela) o total de bytes enviados para o readyState 0 e 1 será 0 e o total para o readyState 2 será o total de bytes na string que você passou. O total de bytes enviados e recebidos em readyState 3 e 4 será a soma dos bytes na string original mais o total de bytes em 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 você tiver acesso ao seu Apache, instale e confie em código de terceiros, você pode usar o módulo de progresso de upload do Apache (se você usa o Apache; há também um módulo de progresso de upload do nginx ).

Caso contrário, você teria que escrever um script que você pode bater fora da banda para solicitar o status do arquivo (verificando o tamanho do arquivo do arquivo tmp, por exemplo).

Há algum trabalho acontecendo no firefox 3 Acredito que adicionar suporte ao progresso de upload para o navegador, mas isso não vai entrar em todos os navegadores e ser amplamente adotado por um tempo (mais é a pena).

2
Aeon