web-dev-qa-db-fra.com

Comment obtenir des progrès de XMLHttpRequest

Est-il possible d'obtenir la progression d'un XMLHttpRequest (octets téléchargés, octets téléchargés)?

Cela serait utile pour afficher une barre de progression lorsque l'utilisateur télécharge un fichier volumineux. L'API standard ne semble pas le prendre en charge, mais peut-être existe-t-il une extension non standard dans l'un des navigateurs existants? Cela semble être une caractéristique assez évidente après tout, car le client sait combien d'octets ont été chargés/téléchargés.

note: je suis au courant de l'option "interroger le serveur pour connaître les progrès" (c'est ce que je suis en train de faire). Le principal problème avec cela (à part le code compliqué côté serveur) est que, généralement, lors du téléchargement d'un fichier volumineux, la connexion de l'utilisateur est complètement bloquée, car la plupart des FAI offrent une mauvaise qualité amont. Donc, faire des demandes supplémentaires n'est pas aussi réactif que je l'espérais. J'espérais qu'il y aurait un moyen (peut-être non standard) d'obtenir cette information, que le navigateur possède à tout moment.

130
Pete

Pour les octets téléchargés, c'est assez simple. Il suffit de surveiller le xhr.upload.onprogress un événement. Le navigateur connaît la taille des fichiers qu’il doit télécharger et la taille des données téléchargées afin de pouvoir fournir les informations de progression.

Pour les octets téléchargés (lors de l'obtention de l'info avec xhr.responseText), c'est un peu plus difficile, car le navigateur ne sait pas combien d'octets seront envoyés dans la requête du serveur. La seule chose que le navigateur sait dans ce cas est la taille des octets qu’il reçoit.

Il existe une solution pour cela, il suffit de définir un Content-Length en-tête sur le script du serveur, afin d’obtenir la taille totale des octets que le navigateur va recevoir.

Pour plus, allez à https://developer.mozilla.org/en/Using_XMLHttpRequest .

Exemple: Mon script serveur lit un fichier Zip (cela prend 5 secondes):

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

Maintenant, je peux surveiller le processus de téléchargement du script du serveur, car je sais que sa longueur totale est la suivante:

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

Il y a une bonne discussion de l'indicateur de progrès pour AJAX pattern ici:

http://ajaxpatterns.org/Progress_Indicator

Une des approches les plus prometteuses semble ouvrir un deuxième canal de communication au serveur pour lui demander quelle part du transfert a été effectuée.

8
Sean McMains
7

Pour le total des téléchargements, il ne semble pas y avoir de moyen de gérer cela, mais il y a quelque chose de similaire à ce que vous voulez télécharger. Une fois que readyState a la valeur 3, vous pouvez régulièrement interroger responseText pour obtenir tout le contenu téléchargé jusqu'à présent sous forme de chaîne (cela ne fonctionne pas dans IE), jusqu'à ce que tout le contenu soit disponible, auquel moment il passera à readyState 4. Le total les octets téléchargés à un moment donné seront égaux au nombre total d'octets de la chaîne stockée dans responseText.

Pour une approche tout ou rien de la question de téléchargement, étant donné que vous devez passer une chaîne pour le téléchargement (et qu'il est possible de déterminer le nombre total d'octets), le nombre total d'octets envoyés pour readyState 0 et 1 sera égal à 0 et le total pour readyState. 2 correspondra au nombre total d'octets de la chaîne que vous avez transmise. Le nombre total d'octets envoyés et reçus dans les états readyState 3 et 4 correspondra à la somme des octets de la chaîne d'origine et du nombre total d'octets dans 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 vous avez accès à votre installation Apache et faites confiance à du code tiers, vous pouvez utiliser le module de progression du téléchargement Apache (si vous utilisez Apache, il existe également un module de progression du téléchargement nginx ).

Sinon, vous devrez écrire un script que vous pouvez utiliser hors bande pour demander le statut du fichier (en vérifiant la taille du fichier tmp, par exemple).

Il me semble que certains travaux sont en cours dans firefox 3, je pense, pour ajouter un support de progression de chargement au navigateur, mais cela ne va pas entrer dans tous les navigateurs et être largement adopté pendant un certain temps (plus dommage).

2
Aeon