Lanti Lanti - 3 months ago 18
jQuery Question

jQuery Deferred not executing asynchronously with getJSON call

My problem is

b()
executing lastly, but it should be 2nd in the order. I want to call a JSON api on every click on a button (and always send new api call), but it should remove the last api message from the div:

$(document).ready(function() {

function test() {

function a() {
$("#message-quote, #message-person").empty();
console.log('p1');
};

function b() {
console.log('p2 - before getJSON');
$.getJSON("http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1&callback=", function(a) {
$("#message-quote").append(a[0].content)
$("#message-person").append("<p>— " + a[0].title + "</p>")
console.log('p2 - in getJSON');
});
};

function c() {
$("body, .button, .quote-icons a").css("background-color", "red");
$(".quote-text").css("color", "red");
console.log('p3');
};

var d = $.Deferred(),
p = d.promise();
p.then(a()).then(b()).then(c());
d.resolve();
};

$("#getMessage").on("click", function() {
test();
});

});


The order I got is:

"p1"
"p2 - before getJSON"
"p3"
"p2 - in getJSON"

Answer

Your not waiting for the return of b(), you need to chain the promises due to it calling Asynchronously.

if you return a promise out of b(), it should then wait for result of getJSON to be return before it continues.

also, your functions are executing straight away, .then(callback) needs to take a function it can execute later, where your executing a function straight away instead

function b() {

      return $.getJSON("http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1&callback=", function(a) {
        $("#message-quote").append(a[0].content)
        $("#message-person").append("<p>— " + a[0].title + "</p>")
        console.log('p2');
        // resolve the promise, the call has been completed
      });
    };

 var d = $.Deferred(),
    p = d.promise();
    p.then(a)
     .then(b)
     //the context of .then will now be the promise out of b()
     .then(c);
    d.resolve();

Note : Promises will need to also be returned form each other method.

EDIT: as Rocket pointed out, jQuery Ajax calls implement the promise methods

working example : https://jsfiddle.net/rsfxpg38/4/

you can see an example of it from this post : How do I chain a sequence of deferred functions in jQuery 1.8.x?