-1

Why does this code not work?

It should wait for step 1 to load before loading step 2.Currently, step 2 fires first. I am using mockjax to simulate the Ajax calls.

$.mockjax({
    url: "/step1",
    responseTime: [3000, 4000],
    responseText: {
      status: "success",
      text: "Loading Step 1"
    }
});

$.mockjax({
    url: "/step2",
    responseTime: [100, 200],
    responseText: {
      status: "success",
      text: "Loading step 2"
    }
});


$.getJSON("/step1").then( function(response) {
    return  $("#message").html( "message: " + response.text );
})
.then(
    $.getJSON("/step2", function(response) {
            $("#message").html( "message: " + response.text );
    })                
)
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
AnotherMike
  • 2,633
  • 2
  • 16
  • 15

3 Answers3

1

getJSON step2 fires first because it has a shorter delay and you are effectively firing off both $.getJSON's at the same time

try this instead

$.getJSON("/step1").then( function(response) {
    return  $("#message").html( "message: " + response.text );
})
.then(
    function() { // added this
        $.getJSON("/step2", function(response) {
            $("#message").html( "message: " + response.text );
        })         
    } // and added this
)
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
0

The accepted answer isn't quite correct. It's not really chaining the promises because this:

$("#message").html( "message: " + response.text )

is a synchronous function and does not return a promise. Therefore returning the value it returns does not create a promise chain. It works for this example but you'll get into trouble as you add more and more promises.

The correct way to chain a promise is to return a promise:

someFunction().then(function(){return promise}).then(function(){});

So for your example the correct way to chain is:

$.getJSON("/step1")
.then( function(response) {
    $("#message").html( "message: " + response.text );
    return $.getJSON("/step2"); // <-------------- return a promise!
})
.then(function(response){
    $("#message").html( "message: " + response.text );
})
slebetman
  • 109,858
  • 19
  • 140
  • 171
  • Sorry, but this answer is just wrong. A `.then()` handler is allowed to run synchronous code that returns a value - it does not have to return a promise. If doing so, the next `.then()` handler in the chain will run when the synchronous code is done. Remember, the return value of the `.then()` handler is passed to the next `.then()` handler in the chain as a function argument. It's not the return value from the `.then()` itself. – jfriend00 Sep 04 '15 at 07:37
  • This is NOT like object chaining where each method has to return the object itself (that is already taken care of by the `.then()` method itself). This works quite differently than that. `$.mockjax().then(...). then(...)` runs just fine regardless of what code runs inside the `.then()` handlers. What runs inside the `.then()` handlers determines the timing of when the `.then()` callbacks are called. If you return a promise, then it waits until that promise is resolved before continuing the chain. If you return a value, that value is just passed to the next `.then()` handler. – jfriend00 Sep 04 '15 at 07:40
-1

UPDATE: as per comments, $.when() is unnecessary here and should be used when looking to combine multiple Promises.

I would recommend looking at using when - jsFiddle example here.

    $.mockjax({
    url: "/step1",
    responseTime: [3000, 4000],
    responseText: {
      status: "success",
      text: "Loading Step 1"
    }
});

$.mockjax({
    url: "/step2",
    responseTime: [100, 200],
    responseText: {
      status: "success",
      text: "Loading step 2"
    }
});


$.when($.getJSON("/step1"))
    .then( function(data, textStatus, jqXHR) {
        $("#message").html( "message: " + data.text );
    })
    .then(
        $.getJSON("/step2", function(data, textStatus, jqXHR) {
            $("#message").html( "message: " + data.text );
    })                
)
Keith
  • 168
  • 1
  • 11
  • 1
    There is no reason to involve `$.when()` here. That is only useful when you have more than one promise that are running in parallel and you want to know when all of them are done. The OP is attempting to do serial chaining and not attempting to run requests in parallel. – jfriend00 Sep 04 '15 at 07:36
  • Thanks for the pointer. Do you have any links to further reading on this? I am a little confused based on the start of the jQuery $.when() docs (https://api.jquery.com/jquery.when/) - the first section discusses passing a single Deferred and follows it with $.then(). – Keith Sep 05 '15 at 02:00
  • 1
    Passing a single promise to `$.when()` works, there's just no point. You can just do `$.getJSON(...).then(...)` so there's no point in doing `$.when($.getJSON(...)).then(...)`. The `$.when()` with a single promise is just extra, unnecessary code. The usefulness of `$.when()` is when you have multiple promises. – jfriend00 Sep 05 '15 at 04:13