2

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.

1
  • It seems like jquerys promise does not support flattening the promise, aka return new Promise inside of then Commented Feb 10, 2018 at 16:41

2 Answers 2

5

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()
Sign up to request clarification or add additional context in comments.

2 Comments

So the best way is to move on to jQuery 3, if possible.
@BenjaminH Or that, yeah. But I still like native promises better than jQuery 3 promises, especially missing Promise.all.
1

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

4 Comments

please read the question carefully. he knew the root cause, just did not understand why.
Hi Kai, I edited a bit the answer, I explained better the relation of kyle simpson text with his root cause.
Well, nope, that "new concept layered" is not the root cause for the incompatibility at all. There are many ES5 promise libs that work fine with ES6 promises.
Thanks, Bergi, always good to learn deeply. I just saw, what you answered of Promises/A+, good to know!!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.