web-dev-qa-db-fra.com

Barre de progression lors du téléchargement de fichiers volumineux avec XMLHttpRequest

J'essaie de télécharger des fichiers volumineux sur le serveur à l'aide de XMLHttpRequest et file.slice.
J'ai réussi à le faire à l'aide de documentations et d'autres liens divers. 
Le téléchargement de fichiers volumineux étant un travail de longue haleine, j'aimerais fournir à l'utilisateur une barre de progression.
Après plusieurs lectures, je suis tombé sur un exemple qui, en théorie, fait exactement ce dont j'ai besoin. 
En prenant l'exemple de code et en l'adaptant à mes besoins, j'ai atteint

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

L'appel est comme (sans les validations)

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

Mon problème est que l'événement progress ne se déclenche pas. 
J'ai essayé xhr.addEventListener et avec xhr.upload.addEventListener (chacun à la fois et les deux à la fois) pour l'événement progress mais il ne se déclenche jamais. Les événements onreadystatechange et load se déclenchent parfaitement.

J'apprécierais grandement l'aide avec ce que je fais mal

Mettre à jour
Après plusieurs tentatives, j’ai réussi à simuler une progression, mais j’ai rencontré un autre problème: l’interface utilisateur de Chrome ne se met pas à jour pendant le téléchargement.
Le code ressemble à ceci maintenant

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 + '%';
    }
};


Mise à jour 2
J'ai réussi à le réparer et à simuler une barre de progression qui fonctionne également en chrome.
J'ai mis à jour le code précédent avec celui qui fonctionne.
Vous pouvez "actualiser" la barre plus souvent en réduisant la taille du bloc chargé à la fois Merci de votre aide.

13
Cioby

Comme indiqué dans https://stackoverflow.com/a/3694435/460368 , vous pouvez effectuer les tâches suivantes:

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

et

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 + '%';
   }
}
5
Shikiryu

Il y a ma solution:

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 < 1)
{

}
else
{
xhr.send(fd);
}


}
1
koca79331