Promise chain continues after rejection

I’m having trouble to properly catch an error/reject in a promise chain.

const p1 = () => {
    return new Promise((resolve, reject) => {
        console.log("P1");
        resolve();
    });
};

const p2 = () => {
    return new Promise((resolve, reject) => {
        console.log("P2");
        reject();
    });
};


const p3 = () => {
    return new Promise((resolve, reject) => {
        console.log("P3");
        resolve();
    });
};

p1().catch(() => {
    console.log("Caught p1");
}).then(p2).catch(() => {
    console.log("Caught p2");
}).then(p3).catch(() => {
    console.log("Caught p3");
}).then(() => {
    console.log("Final then");
});

When the promise is rejected, the following .then still gets executed. In my understanding, when in a promise chain an error/reject happened, the .then calls that follow it are not executed any more.

P1
P2
Caught p2
P3
Final then

The rejection gets caught correctly, but why is "P3" logged after the catch?

What am I doing wrong?

To clarify @evolutionxbox, this is my expected result:

Promise.resolve().then(() => {
    console.log("resolve #1");
    return Promise.reject();
}).then(() => {
    console.log("resolve #2");
    return Promise.resolve();
}).then(() => {
    console.log("resolve #3");
    return Promise.resolve();
}).then(() => {
    console.log("Final end");
}).catch(() => {
    console.log("Caught");
});

This code works exactly like it should. And I can’t see a difference to my code, except that I declared the functions separately.

The code above stops no matter where the promise is rejected.

29 thoughts on “Promise chain continues after rejection”

  1. You do not do anything wrong.
    In your code you call the first promise p1. Then you write p1.catch(...).then(...).then(...).then(...). This is a chain which means that you should call then 3 times, because you called resolve method in the p1 promise (all these thens depend on the first promise).

    Reply
  2. Try this.

    const p1 = (arg) => {
      // Promise returns data in the respected arguments
      return new Promise((resolve, reject) => {
        // Data to be accessed through first argument.
        resolve(arg);
    
      });
    };
    
    
    const p2 = (arg) => {
      return new Promise((resolve, reject) => {
    
        // Data to be accessed through second argument.
        reject(arg);
    
      });
    }
    
    p1('p1').then(resolve => {
      console.log(resolve + ' is handled with the resolve argument. So it is accessed with .then()');
    }) // Since reject isn't configured to pass any data we don't use .catch()
    
    p2('p2').catch(reject => {
      console.log(reject + ' is handled with the reject argument. So it is accessed with .catch()');
    }) // Since resolve ins't configured to pass any data we don't use .then()
    
    // You would normally configure a Promise to return a value on with resolve, and access it with .then() when it completes a task successfully.
    
    // .catch() would then be chained on to the end of .then() to handle errors when a task cannot be completed.
    
    // Here is an example.
    
    const p3 = () => {
      return new Promise((resolve, reject) => {
    
        var condition = true;
    
        if (condition === true) {
          resolve('P3');
        } else {
          reject('Promise failed!');
        }
    
      });
    };
    
    p3('p3').then(resolve => {
      console.log(resolve);
    }).catch(reject => {
      console.log(reject);
    })
    Reply
  3. When the promise is rejected, the following .then still gets executed.

    Yes. Just to be accurate: the then and catch method calls are all executed synchronously (in one go), and so all promises involved are created in one go. It’s the callbacks passed to these methods that execute asynchronously, as the relevant promises resolve (fullfill or reject).

    In my understanding, when in a promise chain an error/reject happened, the .then calls that follow it are not executed any more.

    This is not the case. The promise that a catch returns can either fullfill or reject depending on what happens in the callback passed to it, and so the callbacks further down the chain will execute accordingly when that promise resolves.

    The rejection gets caught correctly, but why is "P3" logged after the catch?

    As in your case the catch callback returns undefined (it only performs a console.log), its promise fullfulls! By consequence, the chained then callback — on that promise — is executed… etc.

    If you want to "stop"

    If you want to keep the chain as it is, but wish to have a behaviour where a rejection leads to no further execution of then or catch callbacks, then don’t resolve the associated promise:

    const stop = new Promise(resolve => null);
    
    const p1 = () => {
        return new Promise((resolve, reject) => {
            console.log("P1");
            resolve();
        });
    };
    
    const p2 = () => {
        return new Promise((resolve, reject) => {
            console.log("P2");
            reject();
        });
    };
    
    
    const p3 = () => {
        return new Promise((resolve, reject) => {
            console.log("P3");
            resolve();
        });
    };
    
    p1().catch(() => {
        console.log("Caught p1");
        return stop; // don't resolve
    }).then(p2).catch(() => {
        console.log("Caught p2");
        return stop;
    }).then(p3).catch(() => {
        console.log("Caught p3");
        return stop;
    }).then(() => {
        console.log("Final then");
    });
    Reply

Leave a Comment