user3729576
user3729576

Reputation: 247

Using 'when' with deferred

    var self = this;

    var arr = Array();

    $.each(files, function(index, file){

        self.fileRead.read(file).done(function() {

                arr.push(self.fileShow().done();
        })

    });

    $.when.apply($, arr).done(function(){console.log('all done')});

self.fileRead returns a deferred, as does, self.fileShow.

Here's what I'm trying to do:

For each files, read the file, when this is done, show the file. When EVERY file has been shown, log 'all done'.

The problem is 'all done' is being logged straight away.

I have also looked at map but with no luck, it seems that methods such as self.fileShow are not even ran.

$.when.apply(files, $.map(function(index, file) {
        return self.fileRead.read(file).done(function() {

                return (self.fileShow());
        })

    })).done(function(){console.log('when done')});

Code for file read:

var fileReader = new FileReader();
    var deferred = $.Deferred();

    fileReader.onload = function(event) {

        deferred.resolve(event.target.result);
    };

    fileReader.onerror = function() {
        deferred.reject(this);
    };

    fileReader.readAsDataURL(file);

    return deferred.promise();

Code for file show (just a deferred at the minute):

var deferred = $.Deferred();
    deferred.resolve();
    return deferred.promise();

Upvotes: 0

Views: 248

Answers (1)

Mark Vayngrib
Mark Vayngrib

Reputation: 994

The reason is that you're printing before anything gets put in arr (you only push a promise into arr after a file is read and shown).

If you're using jQuery < 1.8, you can return your own Deferred object in $.map and resolve it when the file has been read and shown.

var self = this;
$.when.apply($, $.map(files, function(index, file) {
    var dfd = $.Deferred();
    self.fileRead.read(file).done(function() {
      self.fileShow().done(dfd.resolve).fail(dfd.reject);
    }).fail(dfd.reject);

    return dfd.promise();
})).done(function() {console.log('when all done')})
   .fail(function() {console.log('when at least one failed')});

If you're using jQuery >= 1.8, you can abuse "then", which can be used to chain nested Deferreds (but wastes Deferred objects needlessly):

var self = this;
$.when.apply($, $.map(files, function(index, file) {
    return self.fileRead.read(file).then(function() {
      return self.fileShow();
    });
})).done(function() {console.log('when all done')})
   .fail(function() {console.log('when at least one failed')});

Upvotes: 1

Related Questions