最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to implement Progress Bar and Callbacks with async nature of the FileReader - Stack Overflow

programmeradmin0浏览0评论

I have the FileReader API called within a for loop to iterate through multiple file objects. I'm using FileReader to essentially display preview of images.

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
}

I'm bumping into two issues due to the async nature of the FileReader API. First, the onprogress event fires for each FileReader instance. This gives me progress for each file. Whereas, I intend to display the total progress for all files instead of individual files.

Secondly, I want to perform actions that should only be performed when all instances (one for each file) of the FileReader have completed. Currently, since FileReader is functioning asynchronously, the actions run before FileReader completes it's task. I have searched a lot and yet to come across a solution for these problems. Any help is appreciated.

I have the FileReader API called within a for loop to iterate through multiple file objects. I'm using FileReader to essentially display preview of images.

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
}

I'm bumping into two issues due to the async nature of the FileReader API. First, the onprogress event fires for each FileReader instance. This gives me progress for each file. Whereas, I intend to display the total progress for all files instead of individual files.

Secondly, I want to perform actions that should only be performed when all instances (one for each file) of the FileReader have completed. Currently, since FileReader is functioning asynchronously, the actions run before FileReader completes it's task. I have searched a lot and yet to come across a solution for these problems. Any help is appreciated.

Share Improve this question edited May 8, 2013 at 16:18 Vitor Canova 3,9765 gold badges35 silver badges55 bronze badges asked May 8, 2013 at 14:34 JohnJohn 1,1785 gold badges20 silver badges36 bronze badges 1
  • Using parseInt on numbers is an anti-pattern. If you want to round (or truncate) the (data.loaded / data.total) * 100 value, use Math.round or Math.floor. You might also do the * 100 part first so that the intermediate value isn't quite so small (since it may help prevent loss of precision): var progress = Math.round((data.loaded * 100) / data.total); – T.J. Crowder Commented Nov 17, 2020 at 11:09
Add a comment  | 

1 Answer 1

Reset to default 24

Let's address your second problem first. You need to define your after-completion code in a separate function, and call that function once all the files have uploaded:

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
}

Now, for tracking progress, there are a couple different ways you could address that. Right now you are loading all the files at once, and each file is reporting its own progress. If you don't mind less frequent progress updates, you could simply use the onload handler to report progress each time a file has uploaded. If you want really fine-grained, accurate progress updates, you are going to have to calculate the total size of all the files combined, then keep track of how much of each file has loaded, and use the sum of what has loaded for each file compared to the total size of all files to report progress.

Alternatively, assuming that you are implementing this with a progress bar rather than console.log, you could provide a separate progress bar for each file that's being uploaded, and calculate progress for each file exactly as you're doing it now, then updating the corresponding progress bar. Let me know if any of that needs clarification.

发布评论

评论列表(0)

  1. 暂无评论