Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jquery custom deferred functions

I have three functions i'm trying to run, the first two are doing some async stuff that need data for the third to use. I want the third function to fire only when 1 and 2 are both done. this is the general structure but the final function is firing before 1 and 2 finish.

function run() {
    var data1 = {};
    var data2 = {};

    $.when(first(), second()).done(constructData());

    function first() {
        var d = new $.Deferred();

        //do a bunch of stuff async
        data1 = {};

        d.resolve();
    }
    function second() {


        var d = new $.Deferred();

        //do a bunch of stuff async
        data2 = {};
        d.resolve();
    }
    function constructData() {
        //do stuff with data1 and data2
    }

}

Answer was to not call construct data immediately

 $.when(first(), second()).done(constructData);
like image 505
Brian Avatar asked Feb 22 '13 07:02

Brian


People also ask

What is Deferred () in JQuery?

Deferred() A factory function that returns a chainable utility object with methods to register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function.

How use JQuery Deferred and promise?

promise() will attach the methods onto it and then return this object rather than create a new one. This can be useful to attach the Promise behavior to an object that already exists. If you are creating a Deferred, keep a reference to the Deferred so that it can be resolved or rejected at some point.

What is the difference between a Deferred and a promise?

A promise represents a value that is not yet known. This can better be understood as a proxy for a value not necessarily known when the promise is created. A deferred represents work that is not yet finished. A deferred (which generally extends Promise) can resolve itself, while a promise might not be able to do so.

What is .done in JQuery?

done() method in jQuery is used to add handlers which are to be called when the deferred object is resolved. Parameters: Callbacks: This parameter specifies a function, or array of functions, which are called when the Deferred is resolved.


2 Answers

You should return promise object. You also have an error in this line:

$.when(first(), second()).done(constructData());

it should be

$.when(first(), second()).done(constructData); // don't call constructData immediately

So all together it could be:

function run() {
    var data1 = {};
    var data2 = {};

    $.when(first(), second()).done(constructData);

    function first() {
        return $.Deferred(function() { // <-- see returning Deferred object
            var self = this;

            setTimeout(function() {   // <-- example of some async operation
                data1 = {func: 'first', data: true};
                self.resolve();       // <-- call resolve method once async is done
            }, 2000);
        });
    }
    function second() {
        return $.Deferred(function() {
            var self = this;
            setTimeout(function() {
                data2 = {func: 'second', data: true};
                self.resolve();
            }, 3000);
        });
    }
    function constructData() {
        //do stuff with data1 and data2
        console.log(data1, data2);
    }
}

http://jsfiddle.net/FwXZC/

like image 148
dfsq Avatar answered Oct 04 '22 21:10

dfsq


I think you should have first() and second() return a promise: return d.promise();. From the docs:

If a single argument is passed to jQuery.when and it is not a Deferred or a Promise, it will be treated as a resolved Deferred and any doneCallbacks attached will be executed immediately.

I suspect this might be why the when call is calling constructData too soon.

It's hard to tell from you code, but be sure you are calling d.resolve() after the async operations have completed.

You might find that a more natural approach to explicitly setting data1 and data2 is instead to use the data that is supplied when resolve is called. This would mean that your when call would look something like this:

$.when(first(), second()).done(function(result1, result2) {
    data1 = result1[0];
    data2 = result2[0];

    constructData();
});

Note that the exact format of results supplied to the done method depends on the nature of the deferred objects. If the promises are returned from a call to $.ajax, the results should be of the form [data, statusText, jqXhrObject].

like image 30
nick_w Avatar answered Oct 04 '22 20:10

nick_w