Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement Progress Bar and Callbacks with async nature of the FileReader

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.

like image 333
John Avatar asked May 08 '13 14:05

John


1 Answers

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.

like image 50
undefined Avatar answered Oct 16 '22 14:10

undefined