0

Is the following jQuery code equivalent to how it is done in ES6's way, or should the jQuery way be written differently?

// ES6:

new Promise((resolve, reject) => {
  console.log("start");
  setTimeout(() => resolve("a"), 2000);
}).then(s => {
  console.log(s);
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve("b"), 2000);
  });
}).then(s => {
  console.log(s);
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve("c"), 2000);
  });
}).then(s => {
  console.log(s);
});

// jQuery:

let d = $.Deferred();

d.then(s => {
  console.log(s);
  let d = $.Deferred();
  setTimeout(() => d.resolve("b"), 2000);
  return d.promise();
}).then(s => {
  console.log(s);
  let d = $.Deferred();
  setTimeout(() => d.resolve("c"), 2000);
  return d.promise();
}).then(s => {
  console.log(s);
})

console.log("start");
setTimeout(() => d.resolve("a"), 2000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

It seems:

  1. Not everything can be written in one statement in jQuery. The executor has to be moved out as separate statements in jQuery.
  2. For jQuery, not only promise needs to be involved. The deferred needs to be used, because otherwise there is no way to resolve the promise.
  3. In jQuery, the line return d.promise(); can just be return d;, but is it good to return the deferred? The code that receives the deferred can inadvertently resolve the promise, but if it is chained promises, can any code actually receive the deferred and inadvertently resolve the promise?

Per @Tomalak and @jfriend00's comment, it is found that jQuery's promises can be written this way, similar to ES6 promises:

// jQuery:

$.Deferred(d => {
  console.log("start");
  setTimeout(() => d.resolve("a"), 2000);
}).then(s => {
  console.log(s);
  return $.Deferred(d => {
    setTimeout(() => d.resolve("b"), 2000);
  });
}).then(s => {
  console.log(s);
  return $.Deferred(d => {
    setTimeout(() => d.resolve("c"), 2000);
  });
}).then(s => {
  console.log(s);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Instead of function(resolve, reject), it is function(deferred).

The jQuery.Deferred method can be passed an optional function, which is called just before the method returns and is passed the new deferred object as both the this object and as the first argument to the function.

The passed in deferred is the same as this only if it is a traditional function but not an arrow function. But I think it will be better to use the passed in deferred d instead of using this.

nonopolarity
  • 146,324
  • 131
  • 460
  • 740
  • 1) Yes, since the executor has no access to the `resolve()` function, which is only exposed as a `Deferred` instance member. 2) Exactly. 3) It won't make a difference in a promise chain. There is some additional API is available on the `Deferred`, but once the underlying promise is settled, its state or value cannot be changed anymore, so the extra API can't do damage. – Tomalak Jan 21 '20 at 18:42
  • It's worth pointing out that since jQuery 3.0, `Deferred` instances [are Promises/A+ compatible](https://stackoverflow.com/a/23958233/18771). – Tomalak Jan 21 '20 at 18:45
  • Missing in this discussion is `$.Deferred(def => setTimeout(def.resolve, 100)).then(...);`. – jfriend00 Jan 21 '20 at 23:27
  • You return a deferred to some outside code if you WANT them to have the ability to resolve or reject it themselves. You return `d.promise` if you DON'T want them to have the ability to resolve or reject it themselves, but only to monitor its state changes. That's really the only difference. – jfriend00 Jan 21 '20 at 23:28
  • @jfriend00 if it is all chained up, then if you return a deferrd or promise inside of `then(s => { })` the deferred or promise isn't obtained by anybody else... the only way is for the next `then()` to get invoked. So in this case, it may be best to return `d.promise()` but returning `d` shouldn't have any side or adverse effect. – nonopolarity Jan 23 '20 at 08:17
  • @Tomalak please see the updated info at the end of question – nonopolarity Jan 23 '20 at 08:46
  • FYI, `setTimeout(() => d.resolve("b"),2000)` can be written as `setTimeout(d.resolve, 2000, b)`. – jfriend00 Jan 23 '20 at 22:51

0 Answers0