BenjaminH
BenjaminH

Reputation: 324

jQuery promise execution order differs from javascript promise

The following Promise behaves as expected, the Promise in the return statement gets fulfilled and the then right afterwards gets executed before the last call of then:

(new Promise(resolve => resolve(true)))
.then(function(){
    console.log(0);
    return new Promise(resolve => setTimeout(resolve, 1000))
    .then(function() {
        console.log(1);
    });
}).then(function() {
    console.log(2);
});

The result is

0
1
2

But when the first Promise is a jQuery Promise like in the following case

$.post("index.php")
.then(function() {
    console.log(0);
    return new Promise(resolve => setTimeout(resolve, 1000))
    .then(function() {
        console.log(1);
    });
}).then(function() {
    console.log(2);
});

the result is

0 2 1

which indicates, that the second Promise is not passed on as in standard JavaScript promises.
Is there a way to force the standard behavior?

I'm using jQuery 2.0.0.

Upvotes: 2

Views: 70

Answers (2)

Bergi
Bergi

Reputation: 664920

jQuery 2 does not support Promises/A+, and cannot assimilate promises from other implementations ("thenables"). The native promise that is returned from the callback and resolves the outer promise is not being awaited, but rather used as the immediate fulfillment value. You can see this by inspecting the argument passed to your final callback.

Is there a way to force the standard behavior?

See How to dodge jQuery promises completely when chaining two async jQuery functions? Basically just wrap the $.post("index.php") that starts your chain in Promise.resolve to get a native promise with all its glory (and expected behavior).

The other way round (wrapping the native promise from the timeout in a jQuery promise) I can really not recommend, but it would basically come down to

return $.Deferred(def => promise.then(def.resolve, def.reject)).promise()

Upvotes: 5

Alberto Delgado Roda
Alberto Delgado Roda

Reputation: 471

jQuery(the version you use) maybe doesn't work with the es6 promises, I think they work with something called "defer object", because of that doesn't work.

The great Kyle Simpson, in his book "You don't know Js: Async and performance" writes about promises, this can help you:

"As of ES6, there's a new concept layered on top of the event loop queue, called the "Job queue." The most likely exposure you'll have to it is with the asynchronous behavior of Promises (see Chapter 3)."

Because of that "new concept layered", it is not possible for your jquery version to works well mixing "fake" promises with standard promises.

Trying to overwrite your $.post with:

Promise.resolve($.post("index.php"))
.then(function() {
   console.log(0);
   return new Promise(resolve => setTimeout(resolve, 1000))
     .then(function() {
     console.log(1);
    });
}).then(function() {
 console.log(2);
});

Now your chain of promises are all es6 standard.

The link to Kyle Simpson book:

You Don't Know JS: Async & Performance

And a link to see all the You Don't Know JS series book:

You Don't Know JS

Upvotes: 1

Related Questions