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 |1 Answer
Reset to default 24Let'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.
parseInt
on numbers is an anti-pattern. If you want to round (or truncate) the(data.loaded / data.total) * 100
value, useMath.round
orMath.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