1

So, I was recently introduced to the concept of promises and I was told for chaining purpose, we use 'then', which is actually invoked when the attached promise object is fulfilled. And, to do some work after this object is resolved, I can have a callback inside then which again can return promise. So, if this cb inside 'then' function is returning a promise and 'then' itself return a promise, so, does it mean the 'then' function takes this promise from the cb and directly returns it back as it is. Here is the code:

let p2;

function firstpromise() {
  return new Promise((resolve, reject) => {
    setTimeout
      (
        () => {
          console.log("first promise completed");
          resolve("first promise resolved");
        }, 10000
      );
  });
}
const p = firstpromise();
const pro = p.then((data) => {
  p2 = new Promise((resolve, reject) => {
    setTimeout
      (
        () => {
          console.log("second promise completed" + data);
          resolve("second promise resolved");
        }, 5000
      );
  });
  return p2;
});

console.log(pro === p2);

Both pro and p2 are giving same result on console, once the promise is resolved, so this makes me think that pro and p2 are same. To simplify my confusion: when i write fun1(fun2); i am calling fun1 function and passing fun2 in it. now it is upto fun1 if it calls fun2 or not. Suppose fun2 is called and it returned "hello" to fun1. but fun1 may return "bye" to us. So this whole time we were unaware of any value returned by fun2. so my question is that the function "then" returned a promise, but internally it called secondpromise function which itself "returned promise to then function", so does it mean "then "as it is returned forward the same promise returned to it by second promise function? Also, console.log(pro===p2); actually prints false. If anyone can please explain the internal of then in particular, it would be a great help.. ;)

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    `.then` creates a new promise immediately – Konrad Jul 11 '23 at 19:37
  • 1
    "*we use 'then', which is actually invoked when the attached promise object is fulfilled.*" - no. [There is no magic within promises](https://stackoverflow.com/a/22562045/1048572), and the `.then()` method is invoked right when you call it and returns immediately. It is the *callback* that you pass as an argument that will be invoked later, when the promise fulfills. This alone means that it cannot return the promise that will only be created in the future, it creates a separate promise immediately, that is later resolved to the same result. Notice that `p2` is still `undefined` when you log! – Bergi Jul 11 '23 at 20:21
  • I was certain this was asked before, but I couldn't find a good duplicate. https://stackoverflow.com/q/34094806, https://stackoverflow.com/q/35747957, https://stackoverflow.com/q/65539446, https://stackoverflow.com/q/44765714 just touch on the topic but don't focus on it – Bergi Jul 11 '23 at 21:06

2 Answers2

0

From the documentation of Promise.prototype.then()

The then() method of Promise instances takes up to two arguments: callback functions for the fulfilled and rejected cases of the Promise. It immediately returns an equivalent Promise object, allowing you to chain calls to other promise methods.

Notice that it returns immediately, it doesn't wait for the callback to return. So unless it can predict the future, it can't possibly return the same promise that the callback returns.

The promise that it's equivalent to is the one that it was called on, not the one returned by the callback.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • What do you mean by "*the promise that it's equivalent to*"? – Bergi Jul 11 '23 at 20:23
  • When the documentation says "it returns an equivalent Promise object", it's saying that it returns a promise equivalent to the promise that `.then()` was called on. – Barmar Jul 11 '23 at 20:27
  • E.g. `promise1.then()` returns a promise that's equivalent to `promise1`. – Barmar Jul 11 '23 at 20:28
  • But OP is talking about the case where a callback is passed, i.e. `promise1.then(…)` or more specifically `promise3 = promise1.then(… => { …; return promise2; })`, where `promise3` is definitely not equivalent to `promise1`. – Bergi Jul 11 '23 at 20:30
  • That promise is irrelevant. The text in the above documentation is referring to the promise that's being thenned. I didn't include the whole paragraph. – Barmar Jul 11 '23 at 20:32
  • @Bergi I've added the preceding sentence so the context is clearer. I assumed the link would be sufficient. – Barmar Jul 11 '23 at 20:34
  • MDN is getting worse apparently, "*an equivalent Promise object*" doesn't really make sense (especially without further qualification). No, `promise3` is not equivalent to `promise1`, it's a different object and resolves to a different value. What did you understand "equivalent" to mean? – Bergi Jul 11 '23 at 20:36
  • It just referred to "the Promise" in the previous sentence. No other promise has been mentioned, so that's what "an equivalent Promise" has to refer to. – Barmar Jul 11 '23 at 20:41
  • Ok, now that we've done the grammatical analysis, do you think that statement is correct? Do you believe everything that's written on MDN? Does this match your own experience of using promises? – Bergi Jul 11 '23 at 20:45
  • I don't have much experience outside of answering SO questions, I haven't used them in my professional programming. But the rest of my answer explains why this has to be true, due to the order that things are processed. The other answer explains it in slightly different words, but we're saying the same thing. – Barmar Jul 11 '23 at 20:46
  • Your answer correctly explains why `promise3` cannot be the *same* promise object as `promise2`. And yet, it is equivalent to it insofar as it will resolve to the exact same value as `promise2`, which is [the main idea behind promises](https://stackoverflow.com/a/22562045/1048572). It is not equivalent to `promise1` in any way. – Bergi Jul 11 '23 at 20:53
  • They resolve to the same value because when a promise resolves to another promise, we automatically recurse to get what the 2nd promise resolves to. – Barmar Jul 11 '23 at 20:55
  • Yes, `promise3` is resolved with the return value of the callback, which is `promise2`, it does not resolve to the result of `promise1`. So it's not equivalent to `promise1`. – Bergi Jul 11 '23 at 20:56
  • If you do `console.log(promise3)` it will not log the value of `promise2` because that promise doesn't exist yet. – Barmar Jul 11 '23 at 21:00
  • It will *eventually*, once `promise1` is fulfilled. Until then, it's pending. – Bergi Jul 11 '23 at 21:02
0

In short, the promise returned from then() is not the same promise as the one returned in the callback. When you call then() on a promise a new promise is returned immediately, which is resolved (or rejected) after the the callbacks have run.

Since the promise are asynchronous, it can't wait for the callbacks to be processed before returning anything (and if the base promise never resolves, they would never be processed). If that was the case then a chained promise could never act on the result of a previous one (like fetching data from an external source)

Here is an example of what would happen if it needed to wait for the callback.

// Fetch returns a promise which will resolve when the request is done
const promise1 = fetch('example.com');

// Adding another promise to the chain with .then() is simply saying
// "when the previous promise resolves, do this next". In this case the
// next thing would be to parse the result as json. Since this callback
// depends on the response from fetch, it can't be called until the response
// is available.
// response.json() in turn returns a new promise (much like in your example)
// which will resolve when the json is fully loaded and parsed.
const promise2 = promise1.then(response => response.json());

// when the data has been parsed, maybe we process it or log it or something
const promise3 = promise2.then(data => { /* Process data */ });

// Logging promise3 here will show a pending promise, which is waiting
// for all the previous promises to execute since it is part of the "chain"
// and when we get here "fetch" is most likely just starting the request
// and no callbacks will have been called yet, but we still have a promise
// of a future resolt of some sort.
console.log(promise3);

Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

Karl-Johan Sjögren
  • 16,544
  • 7
  • 59
  • 68