Fortschrittsbalken beim Hochladen großer Dateien mit XMLHttpRequest

Lesezeit: 5 Minuten

Benutzer-Avatar
Cioby

Ich versuche, einige große Dateien mit XMLHttpRequest und file.slice auf den Server hochzuladen.

Ich habe es mit Hilfe von Dokumentationen und anderen verschiedenen Links geschafft.
Da das Hochladen großer Dateien eine langwierige Aufgabe ist, möchte ich dem Benutzer einen Fortschrittsbalken zur Verfügung stellen.
Nach einigen weiteren Lesungen bin ich auf eine gestoßen Beispiel das macht theoretisch genau das, was ich brauche.
Indem ich den Beispielcode nahm und ihn an meine Bedürfnisse anpasste, erreichte ich

var upload =
{
blobs: [],
pageName: '',
bytesPerChunk: 20 * 1024 * 1024,
currentChunk: 0,
loaded: 0,
total: 0,
file: null,
fileName: "",

uploadChunk: function (blob, fileName, fileType) {
    var xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
            if (xhr.responseText) {
                // alert(xhr.responseText);
            }
        }
    };

    xhr.addEventListener("load", function (evt) {
        $("#dvProgressPrcent").html("100%");
        $get('dvProgress').style.width="100%";
    }, false);

    xhr.addEventListener("progress", function (evt) {
        if (evt.lengthComputable) {
            var progress = Math.ceil(((upload.loaded + evt.loaded) / upload.total) * 100);
            $("#dvProgressPrcent").html(progress + "%");
            $get('dvProgress').style.width = progress + '%';
        }
    }, false);

    xhr.upload.addEventListener("progress", function (evt) {
        if (evt.lengthComputable) {
            var progress = Math.ceil(((upload.loaded + evt.loaded) / upload.total) * 100);
            $("#dvProgressPrcent").html(progress + "%");
            $get('dvProgress').style.width = progress + '%';
        }
    }, false);

    xhr.open('POST', upload.pageName, false);

    xhr.setRequestHeader("Content-Type", "multipart/form-data");
    xhr.setRequestHeader("X-File-Name", fileName);
    xhr.setRequestHeader("X-File-Type", fileType);
    xhr.send(blob);
},
upload: function (file) {
    var start = 0;
    var end = 0;
    var size = file.size;

    var date = new Date();
    upload.fileName = date.format("dd.MM.yyyy_HH.mm.ss") + "_" + file.name;

    upload.loaded = 0;
    upload.total = file.size;

    while (start < size) {
        end = start + upload.bytesPerChunk;
        if (end > size) {
            end = size;
        }

        var blob = file.slice(start, end);
        upload.uploadChunk(blob, upload.fileName, file.type);
        start = end;
        upload.loaded += start;
    }

    return upload.fileName;
}
};

Der Anruf ist wie (ohne die Validierungen)

upload.upload(document.getElementById("#upload").files[0]);

Mein Problem ist, dass das Fortschrittsereignis nicht ausgelöst wird.
Ich habe xhr.addEventListener und mit xhr.upload.addEventListener (jeweils und beide gleichzeitig) für das Fortschrittsereignis ausprobiert, aber es wird nie ausgelöst. Die Ereignisse onreadystatechange und load werden problemlos ausgelöst.

Ich würde mich sehr über Hilfe bei dem, was ich falsch mache, freuen

Aktualisieren

Nach vielen Versuchen ist es mir gelungen, einen Fortschritt zu simulieren, aber ich bin auf ein anderes Problem gestoßen: Die Benutzeroberfläche von Chrome wird während des Uploads nicht aktualisiert.
Der Code sieht jetzt so aus

var upload =
{
    pageName: '',
    bytesPerChunk: 20 * 1024 * 1024,
    loaded: 0,
    total: 0,
    file: null,
    fileName: "",

    uploadFile: function () {
        var size = upload.file.size;

        if (upload.loaded > size) return;

        var end = upload.loaded + upload.bytesPerChunk;
        if (end > size) { end = size; }

        var blob = upload.file.slice(upload.loaded, end);

        var xhr = new XMLHttpRequest();

        xhr.open('POST', upload.pageName, false);

        xhr.setRequestHeader("Content-Type", "multipart/form-data");
        xhr.setRequestHeader("X-File-Name", upload.fileName);
        xhr.setRequestHeader("X-File-Type", upload.file.type);

        xhr.send(blob);

        upload.loaded += upload.bytesPerChunk;

        setTimeout(upload.updateProgress, 100);
        setTimeout(upload.uploadFile, 100);
    },
    upload: function (file) {
        upload.file = file;

        var date = new Date();
        upload.fileName = date.format("dd.MM.yyyy_HH.mm.ss") + "_" + file.name;

        upload.loaded = 0;
        upload.total = file.size;

        setTimeout(upload.uploadFile, 100);


        return upload.fileName;
    },
    updateProgress: function () {
        var progress = Math.ceil(((upload.loaded) / upload.total) * 100);
        if (progress > 100) progress = 100;

        $("#dvProgressPrcent").html(progress + "%");
        $get('dvProgress').style.width = progress + '%';
    }
};

Aktualisierung 2

Ich habe es geschafft, es zu beheben und einen Fortschrittsbalken zu simulieren, der auch in Chrome funktioniert.
Ich habe das vorherige Codebeispiel mit dem aktualisiert, das funktioniert.
Sie können die Leiste häufiger „aktualisieren“, indem Sie die Größe des jeweils hochgeladenen Chunks verringern. Danke für Ihre Hilfe

  • Verwenden Sie eine Funktion zum Kürzen? document.getElementById Anrufe? Es sieht so aus, als wäre das was $get() tut, aber ich sehe es nirgendwo definiert.

    – Benutzer1091949

    12. April 2013 um 8:21 Uhr

  • ja. aber ich glaube nicht, dass das das problem ist. es funktioniert gut im Lastereignis und setzt es auf 100%

    – Cioby

    12. April 2013 um 8:59 Uhr

  • @Cioby könnten Sie ein JSFiddle Ihrer Lösung hochladen?

    – Froschbandit

    24. Juni 2016 um 22:18 Uhr

Benutzer-Avatar
Shikiryū

Wie in https://stackoverflow.com/a/3694435/460368 angegeben, könnten Sie Folgendes tun:

if(xhr.upload)
     xhr.upload.onprogress=upload.updateProgress;

und

updateProgress: function updateProgress(evt) 
{
   if (evt.lengthComputable) {
       var progress = Math.ceil(((upload.loaded + evt.loaded) / upload.total) * 100);
       $("#dvProgressPrcent").html(progress + "%");
       $get('dvProgress').style.width = progress + '%';
   }
}

  • das Fortschrittsereignis wird immer noch nicht ausgelöst;

    – Cioby

    12. April 2013 um 10:13 Uhr


  • @Cioby Hast du versucht, es asynchron zu machen? xhr.open('POST', upload.pageName, true); w3.org/TR/XMLHttpRequest/#the-open()-Methode

    – Shikiryū

    12. April 2013 um 12:00 Uhr

  • Entschuldigung für die späte Antwort. Ich habe beide Vorschläge ausprobiert, aber ohne Erfolg. Aus Gründen, die ich nicht verstehe, wird das Fortschrittsereignis nicht ausgelöst. Ich habe den Hauptbeitrag mit dem Fortschritt aktualisiert

    – Cioby

    15. April 2013 um 6:42 Uhr

  • @Cioby hast du angehängt upload.onprocess Vor .open('POST', uri, true)?

    – Henry

    28. Juni 2014 um 5:44 Uhr

  • @Henry, danke für den Tipp, den Event-Handler vor das Öffnen und Senden zu setzen, hat funktioniert.

    – M Granja

    15. April 2019 um 17:37 Uhr


Benutzer-Avatar
koca79331

Da ist meine Lösung:

function addImages(id) {
  var files = $("#files").prop("files");
  var file = files[loopGallery];
  var cList = files.length;

  var fd = new FormData();
  fd.append("file", file);
  fd.append("galerie", id);

  var xhr = new XMLHttpRequest();
  xhr.open("POST", "moduls/galerie/uploadimages.php", true);
  xhr.upload.onprogress = function(e) {
    var percentComplete = Math.ceil((e.loaded / e.total) * 100);
    $("#progress").css("display","");
    $("#progressText").text((loopGallery+1)+" z "+cList);
    $("#progressBar").css("width",percentComplete+"%");
  };

  xhr.onload = function() {
    if(this.status == 200) {
      $("#progressObsah").load("moduls/galerie/showimages.php?ids="+id);
      if((loopGallery+1) == cList) {
        loopGallery = 0;
      } else {
        $("#progressBar").css("width", "0%");  
        loopGallery++;
        addImages(id);
      }
    }
  }

  if(cList > 0) {
    xhr.send(fd);
  }
}

1011520cookie-checkFortschrittsbalken beim Hochladen großer Dateien mit XMLHttpRequest

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy