Reputation: 5910
I am currently trying to build a File Uploader using the HTML5 FileAPI. The File Uploader is supposed to handle multiple files and show image previews if the file is an image.
since the FileReader class works asynchronously I want to wait until all the the files have been read. Therefore I am using Deferreds.
A method which reads the file is returning a promise. Another method loops through all files and pushes all promises into an array. Then I'm applying the then() method once all promises have been added to my array.
Now to my problem. Since the then() method is only called once, when I got all promises. I have no chance to process every single promise. What I want to do is, to loop through all my promises once they are all there and return the result.
This is my FileProcessor Object
read: function(file) {
var reader = new FileReader();
var deferred = $.Deferred();
reader.onload = function(event){
deferred.resolve(event.target.result);
};
reader.onerror = function() {
deferred.reject(this);
}
if(/^image/.test(file.type))
reader.readAsDataURL(file);
return deferred.promise();
},
And here comes the FileManager Object's handleFileSelect() method that is supposed to call the FileProcessor.read() method.
handleFileSelect: function(e){
var $fileList = $('#file-list');
var files = e.target.files;
var promises = []; //Promises are going to be stored here
var filestring = '';
var processedFile;
// Loop trough all selected files
for(var i = 0; i < files.length; i++){
// Store the promise in a var...
processedFile = FileProcessor.read(files[i]);
// And push it into the array where the promises are stored
promises.push(processedFile);
}
// Once all deferreds have been fired...
$.when.apply(window, promises).then(function(){
for(var i = 0; i < promises.length; i++){
// PROBLEM HERE: I need to get the
// result from my resolved Deferred
// of every single promise object
console.log(promises[i]);
}
});
},
Am I using the wrong approach for deferreds and promises? Aren't they supposed to be used like I'm trying to do and is there a more elegant way to achieve my purpose?
Upvotes: 1
Views: 2978
Reputation: 18078
I see you heve accepted an answer but you might like to be aware that your handleFileSelect
method can be significantly simplified as follows
handleFileSelect: function(e) {
var promises = $.map(e.target.files, function(file) {
return FileProcessor.read(file);
});
$.when.apply(window, promises).then(function() {
$.each(arguments, function(i, a) {
console.log(a[0]);
});
});
},
Of course it will get more complicated again when you flesh out the result handling but this should give you a nice concise basis.
Upvotes: 1
Reputation: 388446
you can use the arguments object to refer all the values returned by the promise objects
$.when.apply($, promises).then(function () {
for (var i = 0; i < arguments.length; i++) {
var data = arguments[i][0];
// PROBLEM HERE: I need to get the
// result from my resolved Deferred
// of every single promise object
console.log(data);
}
});
Upvotes: 2
Reputation: 665574
Am I using the wrong approach for deferreds and promises?
Yes. In the asynchronous callback you should not access promises
, but only the callback arguments. The return promise of $.when
does resolve with an array of the .resolve()
parameters for each of the promises in the array - you can loop over the arguments
object to access the results:
$.when.apply($, promises).then(function () {
for (var i = 0; i < arguments.length; i++) {
var singleresult = arguments[i][0];
console.log(singleresult);
}
});
Upvotes: 7