user5915670
user5915670

Reputation:

jQuery Deferred/promise not working as expected

Ok, so I've read 1,000,000+ articles on jQuery deferreds and/or promises, and I'm still getting something wrong.

functionOne() {
    var deferred = $.Deferred();

    var request = $.ajax({
        url: 'http://example.com/mypath/etc'
    });

    request.done(function(data) {

        // TODO: I've got stuff here that takes a while.

        deferred.resolve();
    });

    return deferred.promise();
}

functionTwo() {
    // Something that depends on the others being finished.
}

$.when(
    functionOne(), 
    anotherLongRunningFunctionWithAjax())
 .then(
    functionTwo()
);

I need any function(s) in the "when" to fully complete (.ajax done) before the "then" starts. However, the promise returns immediately (as expected), but functionTwo starts, even though functionOne has not called "done".

I'm sure it's a fundamental misunderstanding of deferred and the chain-of-calls.

Edit:

function functionOne() {
    console.log('functionOne called');

    var request = $.ajax({
        url: 'http://example.com/mypath/etc'
    });

    request.done(function(data) {
        console.log('Starting Done.');

        setTimeout(function () {
            console.log('Done finished.');
        }, 5000);
    });

    console.log('Returning promise.');
    return request;
}

function functionTwo() {
    console.log('functionTwo called');
}

$.when(functionOne()).then(functionTwo());

Gives me this in the console:

functionOne called
Returning promise.
functionTwo called (should be called after Done is finished.)
Starting Done.
Done finished.

Upvotes: 2

Views: 1887

Answers (2)

trincot
trincot

Reputation: 351338

Taking the code in your edit, there are two issues:

  1. The timer in functionOne starts after request is resolved, yet you return request. So whatever happens with the timer... it is of not relevance to the returned promise, which at that time is already resolved.

  2. You call functionTwo immediately, instead of passing the function reference for the $.when promise to call back

Here is working code:

function functionOne() {
    console.log('functionOne called');
    console.log('Returning promise.');
    return $.ajax({
        url: 'https://jsonplaceholder.typicode.com/posts/1'
    }).then(function(data) {
        console.log('Starting Done.');
        var dfd = $.Deferred();
        setTimeout(function () {
            console.log('Done finished.');
            dfd.resolve(data); // indicate when you are done
        }, 2000); // 2 seconds will do ;-)
        return dfd.promise(); // you need to return a promise again
    });
}

function functionTwo() {
    console.log('functionTwo called');
}

// don't call functionTwo immediately, leave that to the promise to do:
$.when(functionOne()).then(functionTwo);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Upvotes: 3

charlietfl
charlietfl

Reputation: 171700

you are using an anti-pattern since $.ajax itself returns a promise

Just do

functionOne() {

    var request = $.ajax({
        url: 'http://example.com/mypath/etc'
    });

    request.done(function(data) {
        // TODO: I've got stuff here that takes a while.       
    });

    return request
}

Upvotes: 1

Related Questions