如何使用FileReader的异步特性实现进度条和回调

Joh*_*ohn 10 javascript html5 filereader

我在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
}
Run Code Online (Sandbox Code Playgroud)

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

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

und*_*ned 17

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

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
}
Run Code Online (Sandbox Code Playgroud)

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

或者,假设您使用进度条而不是console.log实现此功能,您可以为要上载的每个文件提供单独的进度条,并准确计算每个文件的进度,然后更新相应的进度条.如果有任何需要澄清,请告诉我.

  • 几分钟后我实施了同样的解决方案并回到这个问题,发现你碰巧建议我实施的内容.对于进度,我不需要粒度值.所以我最终将进度计算为`var progress = parseInt(((loaded/totalNumberOfFiles)*100),10);`.谢谢您的帮助. (2认同)