0

I am learning promise chaining and I stumbled upon a doubt. Consider the below promise chain -

const myPromise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("foo");
    }, 10000);
});

myPromise
    .then(handleFulfilledA, handleRejectedA)  // first then
    .then(handleFulfilledB, handleRejectedB)  // second then
    .then(handleFulfilledC, handleRejectedC); // third then

The promise constructor returns a promise object myPromise. The handleFulfilledA and handleRejectedA are attached to the [[PromiseFulfillReactions]] and [[PromiseRejectReactions]] of myPromise object. The second and the third then method will be called before myPromise is resolved as myPromise takes 10 seconds.

What happens internally when the second and the third .then method is encountered?

I tried to find an answer and came to know that each then method returns a new Promise object. Let's call them promiseB and promiseC. The handleFulfilledB and handleRejectedB are attached to the [[PromiseFulfillReactions]] and [[PromiseRejectReactions]] of promiseB. Similarly, handleFulfilledC and handleRejectedC are attached to promiseC.

But if this is the case, when myPromise is fulfilled and its [[PromiseFulfillReactions]] are executed, how will its reactionhandlers(handleFulfilledA, handleRejectedA) know that it has to resolve or reject promiseB? How will the handler come to know that the then to which it was passed to has created a promise which is promiseB? In other words, how is the connection between the handlers and the new promises established?"

4
  • The second and the third then method will be called before myPromise is resolved as myPromise takes 10 seconds Is it a question or a requirement or a statement? Commented Aug 26, 2024 at 10:38
  • @WiktorZychla statement. That's what happens p.then().then().then() will execute all .then() calls and set up the chains synchronously, before p or any of the other promises returned by .then() are fulfilled or rejected. The handlers attached via the .then() calls will execute later - on fulfilment/rejection (as appropriate). Commented Aug 26, 2024 at 10:41
  • 2
    The one thing that made promises absolutely clear to me was looking at the source code to the various promise libraries that proliferated the interwebs before browsers started implementing "native" Promises, what really helped me even more was writing my own implementation. Commented Aug 26, 2024 at 10:42
  • @JaromandaX related: How is a promise/defer library implemented? Commented Aug 26, 2024 at 10:45

2 Answers 2

0

As per the MDN documentation for the then method:

then() returns a new promise object but mutates the promise object it's called on, appending the handlers to an internal list. Therefore the handler is retained by the original promise and its lifetime is at least as long as the original promise's lifetime.

This should explain why the chaining is possible.

Sign up to request clarification or add additional context in comments.

Comments

0

But if this is the case, when myPromise is fulfilled and its [[PromiseFulfillReactions]] are executed, how will its reactionhandlers(handleFulfilledA, handleRejectedA) know that it has to resolve or reject promiseB?

handleFulfilledA or handleRejectedA will not directly resolve or reject the promiseB.

The promise returned by the first then method call, i.e. promiseB depends on two things:

  • What happens to the original promise, i.e. myPromise, and
  • What happens inside the fulfillment / rejection handler

In your code, as myPromise will be resolved, handleFulfilledA will be called, and depending on what you do inside this handler, promiseB will either resolve or get rejected.

If you return any non-promise value, or implicitly return undefined, promiseB will be fulfilled with that value as its fulfillment value. Similarly, if you throw an error inside the fulfillment handler of myPromise, the promiseB will get rejected with the thrown error as the rejection reason.

Finally, what if you return a promise from the fulfillment handler? In that case, promiseB will get resolved to that promise. This simply means that fate of the promiseB will depend on the promise returned from the fulfillment handler of myPromise. The promiseB will fulfill if the promise returned by the then handler is fulfilled. Similarly, promiseB will get rejected if the promise returned by the then handler is rejected.

Following code example should give you an idea of how outer promise (promiseB) can resolve to the inner promise (returned by the then handler):

const outerPromise = new Promise((resolveOuter, rejectOuter) => {
   const innerPromise = new Promise((resolveInner, rejectInner) => {
      // ...
   });

   // resolve/reject functions of the outer promise are 
   // passed to the `then()` method of the inner promise 
   // as the fulfilment/rejection handlers respectively
   innerPromise.then(resolveOuter, rejectOuter);
});

Recommened reading: Javascript promises ... in wicked detail

Comments

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.