【问题标题】:How to implement Progress Bar and Callbacks with async nature of the FileReader如何使用 FileReader 的异步特性实现进度条和回调
【发布时间】:2013-05-08 14:34:06
【问题描述】:

我在 for 循环中调用 FileReader API 来遍历多个文件对象。我正在使用 FileReader 来显示图像的预览。

function() {
    for (var i in Files) {
        var fileReader = new FileReader();
        fileReader.readAsBinaryString(Files[i]);
        fileReader.onload = function() {

            // do something on FileReader onload

        }

        fileReader.onprogress = function(data) {
            if (data.lengthComputable) {                                            
                var progress = parseInt( ((data.loaded / data.total) * 100), 10 );
                console.log(progress);
            }
        }
    }

    // do something on completion of FileReader process
    // actions here run before completion of FileReader
}

由于 FileReader API 的异步特性,我遇到了两个问题。首先,每个 FileReader 实例都会触发 onprogress 事件。这给了我每个文件的进度。然而,我打算显示所有文件而不是单个文件的总进度。

其次,我想执行仅应在 FileReader 的所有实例(每个文件一个)完成后执行的操作。目前,由于 FileReader 是异步运行的,因此操作会在 FileReader 完成其任务之前运行。我进行了很多搜索,但尚未找到解决这些问题的方法。任何帮助表示赞赏。

【问题讨论】:

  • 在数字上使用parseInt 是一种反模式。如果要舍入(或截断)(data.loaded / data.total) * 100 值,请使用 Math.roundMath.floor。您也可以先执行* 100 部分,这样中间值就不会那么小(因为它可能有助于防止精度损失):var progress = Math.round((data.loaded * 100) / data.total);

标签: javascript html filereader


【解决方案1】:

让我们先解决您的第二个问题。您需要在单独的函数中定义完成后代码,并在所有文件上传后调用该函数:

function() {
    var total = Files.length; loaded = 0;
    for (var i in Files) {
        var fileReader = new FileReader();
        fileReader.readAsBinaryString(Files[i]);
        fileReader.onload = function() {

            // do something on FileReader onload
            loaded++;

            if (loaded == total){
                onAllFilesLoaded();
            }
        }

        fileReader.onprogress = function(data) {
            if (data.lengthComputable) {                                            
                var progress = parseInt( ((data.loaded / data.total) * 100), 10 );
                console.log(progress);
            }
        }
    }
}

function onAllFilesLoaded(){
    //do stuff with files
}

现在,为了跟踪进度,您可以通过几种不同的方式来解决这个问题。现在您正在一次加载所有文件,并且每个文件都在报告自己的进度。如果您不介意不太频繁的进度更新,您可以简单地使用 onload 处理程序在每次文件上传时报告进度。如果您想要真正细粒度、准确的进度更新,您将不得不计算所有文件组合的总大小,然后跟踪每个文件的加载量,并使用每个文件加载的总和文件与所有文件的总大小进行比较以报告进度。

或者,假设您使用进度条而不是 console.log 来实现这一点,您可以为每个正在上传的文件提供一个单独的进度条,并完全按照您现在的方式计算每个文件的进度,然后更新相应的进度条。让我知道是否需要澄清。

【讨论】:

  • 就在几分钟前,我实施了同样的解决方案,然后回到这个问题,发现您碰巧准确地建议了我实施的方案。对于进度,我不需要粒度值。所以我最终将进度计算为var progress = parseInt( ((loaded / totalNumberOfFiles) * 100), 10 );。感谢您的帮助。
  • 太棒了,希望这对其他人也有帮助。
猜你喜欢
  • 2021-11-19
  • 1970-01-01
  • 2020-03-15
  • 1970-01-01
  • 2013-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多