jQuery 使用 XMLHttpRequest 上传大文件时的进度条

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15965651/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 16:07:03  来源:igfitidea点击:

Progress bar while uploading large files with XMLHttpRequest

javascriptjqueryfile-uploadxmlhttprequest

提问by Cioby

I am trying to upload some large files to the server using XMLHttpRequest and file.slice.
I've manage doing this with the help of documentations and other various links.
Since uploading large file is a lengthily job, i would like to provide the user with a progress bar.
After some more readings i've come across on an examplethat, theoretically, does exactly what i need.
By taking the sample code and adapting it to my needs i reached

我正在尝试使用 XMLHttpRequest 和 file.slice 将一些大文件上传到服务器。
我在文档和其他各种链接的帮助下设法做到了这一点。
由于上传大文件是一项漫长的工作,我想为用户提供一个进度条。
经过更多阅读后,我遇到了一个例子,理论上,它完全符合我的需要。
通过获取示例代码并使其适应我的需求,我达到了

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

The call is like (without the validations)

调用就像(没有验证)

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

My problem is that the progress event doesn't trigger.
I've tried xhr.addEventListener and with xhr.upload.addEventListener (each at a time and both at a time) for the progress event but it never triggers. The onreadystatechange and load events trigger just fine.

我的问题是进度事件不会触发。
我已经为进度事件尝试过 xhr.addEventListener 和 xhr.upload.addEventListener (一次一次,一次两次),但它永远不会触发。onreadystatechange 和 load 事件触发得很好。

I would greatly appreciate help with what i am doing wrong

我将不胜感激帮助我做错了什么

Update
After many attempts i've manage to simulate a progress but i've ran into another problem: Chrome's UI is not updating during the upload.
The code looks like this now

更新
经过多次尝试,我设法模拟了一个进度,但我遇到了另一个问题:Chrome 的 UI 在上传过程中没有更新。
代码现在看起来像这样

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


Update 2
I've managed to fix it and simulate a progress bar that works in chrome too.
i've updated previous code sample with the one that works.
You can make the bar 'refresh' more often by reducing the size of the chunk uploaded at a time Tahnk you for your help


更新 2
我已经设法修复它并模拟一个在 chrome 中也可以使用的进度条。
我已经用有效的代码示例更新了以前的代码示例。
您可以通过减少一次上传的块的大小来使栏更频繁地“刷新” 感谢您的帮助

回答by Shikiryu

As stated in https://stackoverflow.com/a/3694435/460368, you could do :

https://stackoverflow.com/a/3694435/460368 所述,您可以:

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

and

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

回答by koca79331

There is my 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 > 0) {
    xhr.send(fd);
  }
}