Filip Vondrášek
Filip Vondrášek

Reputation: 1208

Promises call their success callback too late

I have a code as follows:

products.SaveApplications = function (product) {
    var promises = [];

    ko.utils.arrayForEach(product.Applications(), function (item) {
       var applicationToSend = ko.mapping.toJS(item);
       promises.push($.ajax({
             type: "POST",
             contentType: "application/json",
             url: serviceUrl + "/InsertApplication",
             data: JSON.stringify(applicationToSend),
             success: function (data) {
                 alert("Doing success callback now.");
                 item.ID(data);
             }}));
    });

    return promises;
}

Then a function products.SaveEnvironments, which is basically the same, except it calls a different function in my controller, and a function products.SaveInstallations, which is, again, mostly the same, except it needs to wait for Environments and Applications to save, because it has some dependant data (Application.ID and Environment.ID).

Now I have a function, which calls both these functions and waits for them until both have finished:

products.SaveChanges = function (product) {
    // (...)
    var promises = products.SaveApplications(product);
    promises = promises.concat(products.SaveEnvironments(product));

    $.when(promises).done(function () {
       alert("we shouldn't see this before the other message!");
       products.SaveInstallations(product);
    }); 
};

The problem is that the alert box with "We shouldn't see this message before the other message!" actually appears before the "Doing success callback now", which means my ID properties are null at the time. It leads me to the conclusion that the $.when call only does the actual promises, but doesn't wait for the success callbacks to finish. How can I make it wait? Thank you.

Upvotes: 0

Views: 397

Answers (1)

Jon
Jon

Reputation: 437406

You are using $.when incorrectly. You can't pass multiple promises to it as an array; if you do that, it treats the array just like any other non-promise value and turns it into a completed promise with the array of the still-pending promises as its result. That, of course, is not useful.

You need to use .apply instead to simulate calling $.when with each promise as a separate argument, like this:

$.when.apply(null, promises).done(function () { ... });

Upvotes: 1

Related Questions