it-swarm-eu.dev

So erhalten Sie Fortschritte von XMLHttpRequest

Ist es möglich, den Fortschritt einer XMLHttpRequest zu erhalten (hochgeladene Bytes, heruntergeladene Bytes)?

Dies ist nützlich, um einen Fortschrittsbalken anzuzeigen, wenn der Benutzer eine große Datei hochlädt. Die Standard-API scheint dies nicht zu unterstützen, aber gibt es möglicherweise eine nicht standardmäßige Erweiterung in einem der Browser? Es scheint doch ein ziemlich naheliegendes Feature zu sein, da der Client weiß, wie viele Bytes hochgeladen/heruntergeladen wurden.

hinweis: Mir ist die Alternative "Server nach Fortschritt abfragen" bekannt (das mache ich gerade). Das Hauptproblem dabei (abgesehen vom komplizierten serverseitigen Code) ist, dass die Verbindung des Benutzers beim Hochladen einer großen Datei in der Regel vollständig unterbrochen wird, da die meisten ISPs einen schlechten Upstream bieten. Zusätzliche Anfragen zu stellen ist also nicht so schnell, wie ich es mir erhofft hatte. Ich hatte gehofft, es gäbe eine Möglichkeit (möglicherweise nicht standardgemäß), diese Informationen abzurufen, die der Browser jederzeit zur Verfügung hat.

130
Pete

Für die hochgeladenen Bytes ist es ganz einfach. Überwachen Sie einfach die xhr.upload.onprogress Veranstaltung. Der Browser kennt die Größe der Dateien, die er hochladen muss, und die Größe der hochgeladenen Daten, sodass er die Fortschrittsinformationen bereitstellen kann.

Für die heruntergeladenen Bytes (beim Abrufen der Informationen mit xhr.responseText) ist es etwas schwieriger, da der Browser nicht weiß, wie viele Bytes in der Serveranfrage gesendet werden. Das einzige, was der Browser in diesem Fall weiß, ist die Größe der Bytes, die er empfängt.

Hierfür gibt es eine Lösung. Es reicht aus, ein Content-Length -Header im Serverskript, um die Gesamtgröße der Bytes zu ermitteln, die der Browser empfangen soll.

Weitere Informationen finden Sie unter https://developer.mozilla.org/en/Using_XMLHttpRequest .

Beispiel: Mein Serverskript liest eine Zip-Datei (es dauert 5 Sekunden):

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

Jetzt kann ich den Downloadprozess des Serverskripts überwachen, da ich weiß, dass es sich um die Gesamtlänge handelt:

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

Es gibt eine nette Diskussion über den Fortschrittsindikator für das AJAX Muster hier:

http://ajaxpatterns.org/Progress_Indicator

Einer der vielversprechendsten Ansätze scheint darin zu bestehen, einen zweiten Kommunikationskanal zum Server zu eröffnen, um zu erfragen, wie viel von der Übertragung abgeschlossen wurde.

8
Sean McMains
7

Für die Summe der hochgeladenen Dateien scheint es keine Möglichkeit zu geben, damit umzugehen, aber es gibt eine ähnliche Möglichkeit, wie Sie sie herunterladen möchten. Sobald readyState 3 ist, können Sie periodisch responseText abfragen, um den gesamten Inhalt als String herunterzuladen (dies funktioniert im IE nicht), bis alles verfügbar ist und zu welchem ​​Zeitpunkt der Übergang zu readyState 4 erfolgt. Die Summe Zu einem bestimmten Zeitpunkt heruntergeladene Bytes entsprechen den Gesamtbytes in der in responseText gespeicherten Zeichenfolge.

Da Sie für den Upload eine Zeichenfolge übergeben müssen (und die Gesamtanzahl der Bytes ermitteln können), werden für readyState 0 und 1 insgesamt 0 Bytes und für readyState insgesamt 0 Bytes gesendet 2 ist die Gesamtzahl der Bytes in der Zeichenfolge, die Sie übergeben haben. Die Gesamtzahl der in readyState 3 und 4 gesendeten und empfangenen Bytes ist die Summe der Bytes in der ursprünglichen Zeichenfolge plus der Gesamtzahl der Bytes 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

Wenn Sie Zugriff auf Ihren Apache-Installations- und Vertrauenscode eines Drittanbieters haben, können Sie das Apache-Upload-Fortschrittsmodul (wenn Sie Apache verwenden; es gibt auch ein Nginx-Upload-Fortschrittsmodul ).

Andernfalls müssten Sie ein Skript schreiben, das Sie außerhalb des Bandes aufrufen können, um den Status der Datei anzufordern (z. B. Überprüfen der Dateigröße der tmp-Datei).

Ich glaube, in Firefox 3 wird einiges an Arbeit geleistet, um dem Browser Unterstützung für den Upload-Fortschritt hinzuzufügen, aber das wird nicht in alle Browser gelangen und für eine Weile weit verbreitet sein (mehr ist schade).

2
Aeon