0

I'm trying to resolve a deferred of a promise after a Q.allSettled is finished. However, the .then of the allSettled never executes and the promise array results are never returned. No exceptions are thrown I just never get inside the .then block. As you can see from the code below I'm inside of a .then block iterating over some file upload elements and then executing file uploads and some saves based on those returns.

var deferred = Q.defer();

datacontext.getFileNameGuid(fileNamesNeeded).then(function (data) {                 
     _.each($fileUploads, function(item){
         if (item.files.length > 0) {
            var promise = uploadFile(item, data[remainingFilesToUpload])
                .then(function () {
                    return datacontext.saveItem(atom)
                        .then(function (data) {
                            return getItemSuccess(data, false);
                        }).done();
                }).catch(function (data) {
                    logger.logError("An error occurred while updating your item. Please try again.", data, 'Error', true);                                   
                }).done();

            fileUploadPromises.push(promise);

            return promise;
        }
    });

    // Either execute promises or bail
    if (fileUploadPromises.length > 0) {
        // Handle blockUI and spinner in last then.
        Q.allSettled(fileUploadPromises).then(function () {
            deferred.resolve('Images have been saved and scheduled for thumbnail generation.');
        });
    } else {
        // Other logic here
    }
});

return deferred.promise;
Mike S
  • 1
  • 1
  • First of all, avoid the [deferred antipattern](http://stackoverflow.com/q/23803743/1048572)! – Bergi Mar 29 '16 at 15:39
  • Which of the many `then` callbacks are you never getting into? – Bergi Mar 29 '16 at 15:43
  • There's no reason for any of those `.done()` calls – Bergi Mar 29 '16 at 15:43
  • after the Q.allSettled I need to execute the `then`... I updated my code block above. It had a `done` – Mike S Mar 29 '16 at 15:47
  • So, are you sure that a) `fileUploadPromises.length` is really `> 0` b) all those promises really settle eventually? – Bergi Mar 29 '16 at 15:49
  • Positive. I stepped through this entire thing. The last one I'm expecting to get executed is getItemSuccess and that resolves every time. – Mike S Mar 29 '16 at 15:52
  • You can to add argument to access results explicitly **Q.allSettled(fileUploadPromises).then(function (results) {** - are there any in this case? - if you do **console.log(results);** – shershen Mar 29 '16 at 16:00
  • @Bergi - I figured out my solution. Thanks for showing me the deferred antipattern. I ended up refactoring a bunch to get this very convoluted file upload code to work. Thanks again! – Mike S Mar 30 '16 at 04:48
  • @MikeS: Can you please [post an answer](http://stackoverflow.com/help/self-answer) with the working code? I'm really curious how this was resolved. – Bergi Mar 30 '16 at 14:05

1 Answers1

0

After taking advice from @Bergi I refactored a bunch of code that was using the deferred antipattern. I ended up wrapping my code in a Q.fcall block to return the promise and changed Q.allSettled to Q.all. Below is the end state to my working code.

NOTE: There are function calls to Durandal specific functionality and other functions that I've omitted.

return Q.fcall(function () {
    try {

        var fileUploadPromises = [];
        var $fileUploads = $(fileUploadClass);
        var fileNamesNeeded = 0;

        $fileUploads.each(function (index, item) {
            if (item.files.length > 0)
                fileNamesNeeded++;
        });

        return datacontext.getFileNameGuid(fileNamesNeeded).then(function (data) {
            _.each($fileUploads, function (item) {
                if (item.files.length > 0) {
                    // Init upload file promise                                
                    var promise = uploadFile(item, data[remainingFilesToUpload])
                        .then(function () {
                            return datacontext.saveItem(atom)
                                .then(function (data) {
                                    return getItemSuccess(data, false);
                                });
                        }).catch(function (data) {                                        
                            logger.logError('An error occurred while updating your Item. Please try again.', data, 'Error', true);
                            app.trigger(config.publishedMessageNames.AtomFileUploaded, "");
                        });

                    fileUploadPromises.push(promise);

                    remainingFilesToUpload++;
                }
            });

            // Either execute promises or bail
            if (fileUploadPromises.length > 0) {                            
                return Q.all(fileUploadPromises)
                .then(function (results) {                                
                    return datacontext.scheduleBatchTask(filesToUpload(), item.DocumentId()).then(function () {
                        app.trigger(config.publishedMessageNames.FileUploaded, data);
                    });
                }).done();
            } else {
                app.trigger(config.publishedMessageNames.FileUploaded, "");
            }
        });                   
    } catch (e) {
        return new Error(e);
    }
}); 
Community
  • 1
  • 1
Mike S
  • 1
  • 1