Error propagation in chained Promise not working as expected

async/await error handling best practices
promise javascript
promise chaining
promise then
promise catch
promise finally
uncaught (in promise)
javascript promise w3schools

I'm learning chaining in JS Promises from this site. Based on the high level example, I've written following code to understand error propagation better.

var promise = new Promise((resolve, reject) => {
    reject('Rejected!');
});

promise.then(()=>new Promise ((resolve, reject) => resolve('Done!')), () => console.log('Failure of first Promise'))
       .then(() => console.log('Success of nested Promise'), () => console.log('Failure of nested Promise'));

console.log('This will be still printed first!');

Here when I'm rejecting the first promise, It is giving logging Failure of first Promise and then Success of nested Promise.

Now I wonder how It's going in the success callback of nested Promise? As explained in the above mentioned article, it's clear that even one promise is failed (rejected), the failure callback should be invoked.

What I'm missing here? Thanks.

The code you have written is like

var promise = new Promise((resolve, reject) => { reject('Rejected!'); });
promise
    .then(()=>new Promise ((resolve, reject) => resolve('Done!')))
    .catch(() => console.log('Failure of first Promise'))
    .then(() => console.log('Success of nested Promise'))
    .catch(() => console.log('Failure of nested Promise')); 
    console.log('This will be still printed first!');

since catch also returns a promise, the then chained with catch will also be triggered, if there is only one catch at end of all then, that catch will be triggered without any then.

you can do the following to overcome this issue,

promise
    .then(()=>new Promise ((resolve, reject) => resolve('Done!')))
    .then(() => console.log('Success of nested Promise'))
    .catch(() => console.log('Failure of Promise')); 
    console.log('This will be still printed first!');

Error handling with promises, , so the control jumps to the nearest error handler. Now in your code snippet, wrap the second setTimeout function in a promise and return that promise. Also if you want the small task to be asynchronous then wrap it inside a promise also and return that promise.

Second then callback catches the error from previous promise (catches as in try..catch). In this specific case (there's no chance that first then callbacks result in rejection) this is the same as:

promise // rejected promise
.then(()=>new Promise ((resolve, reject) => resolve('Done!'))) // skips rejected promise
.catch(() => console.log('Failure of first Promise')) // results in resolved promise
.then(() => console.log('Success of nested Promise')) // chains resolved promise
.catch(() => console.log('Failure of nested Promise')); // skips resolved promise

Promise.reject(), One of the great things about using promises is chaining. These make it possible to offer fallback error handling for promises, as well as to help debug issues with You can capture these for analysis and handling by your code—or Unfortunately, some APIs still expect success and/or failure callbacks  Javascript Promises are quite simple to start with, but confusions arise when Promises are chained. This tutorial focuses on the return values of then() and catch(), which are crucial to understanding the process.

This is because

The catch() method returns a Promises

MDN source - Promise.prototype.catch()

"use strict";

new Promise((resolve, reject) => {
  reject('Error');
}).catch(err => {
  console.log(`Failed because of ${err}`);
}).then(() => {
  console.log('This will be called since the promise returned by catch() is resolved');
});

This will log

Failed because of Error This will be called since the promise returned by catch() is resolved

JavaScript Promises - reject vs. throw, They do not receive values; instead, they receive errors, so a developer might In Listing 14-16, the last promise in the chain will be resolved, not rejected, even a rejection callback one might reasonably expect it to propagate, but that isn't  It looks like the initial return from the promise (the one your return with resolve) is the return value used for future chained promises. If you specify a different return value from a function in .then(), the function will be run immediately. I took a look at the code and unfortunately this isnt what (from my brief reading) should be the case

Using Promises, This kind of error is expected. For Promise-based functions that means not mixing rejections and There are two solutions to this problem. can also start a chain of then() method calls via Promise.resolve() and execute  If you attach a .then or .catch handler to a Promise after it’s been cancelled, the chained Promise will be instantly rejected with the error “Promise is cancelled”. If you cancel a Promise immediately after creating it in the same Lua cycle, the fate of the Promise is dependent on if the Promise handler yields or not.

JavaScript Frameworks for Modern Web Dev, The end of the chain has a catch function to handle any problems that may occur an error inside a catch callback if you want the rejection to continue propagating happy path and consider your work done once things behave as expected. The "invisible try..catch " around the executor automatically catches the error and turns it into rejected promise. This happens not only in the executor function, but in its handlers as well. If we throw inside a.then handler, that means a rejected promise, so the control jumps to the nearest error handler.

Promise-based functions should not throw exceptions, Not using try/catch with async/await could result to (node:11) This article is intended to suggest a better way to handle errors when using The example below use promises to solve callback hell by using multiple chained Async/​await is a special syntax to work with promises in a more concise way. You are basically saying, "once this promise is fulfilled, run one of two code paths. You are not saying, "once this promise is fulfilled, run this code path or throw an exception." If you want the exception behavior then promises are not the right answer. You want some other construct that, while similar, does not keep rejected promises around.

Comments
  • Rethrow the error if it needs to propagate down error => throw error; or throw a new error inside the rejection handlers if you need to change some of the error objects properties. error => throw new Error( 'some other error description' );.