Skip to content Skip to sidebar Skip to footer

Promise Then And Catch Clauses Not Working

Background I have a multitude of functions that may or may not return a Promise and that may or may not fail, like in the examples below: let goodFun = (fruit) => `I like ${frui

Solution 1:

The problem here is that you are misunderstanding how Promise.all() works. The way it works is that if all of the promises succeed, it resolves to an array of values. If any of them fail, it rejects with the first error that occurred.

What you seem to be expecting, that the successful ones are caught in the then and the failed ones are caught in the catch, is not possible. A promise either resolves once or it rejects once. It doesn't do both, and it won't do one or the other multiple times. Promise.all() returns a single promise so it will either resolve or reject.

Third party promise libraries do have methods for "settling" an array of promises - basically waiting until they have all done their thing (succeeded or failed), and resolving to an array of the results. You can implement it like this:

// values is an array of promises and/or non-promise valuesfunctionallSettled(values) {
  letsettle =
    value => Promise.resolve(value)
    .then(result => ({ state: "fulfilled", value: result }))
    .catch(error => ({ state: "rejected", reason: error }));

  returnPromise.all(values.map(settle));
}

// example usageallSettled(['hello', 'goodbye', Promise.resolve('good'), Promise.reject('bad')])
  .then(results =>console.log(results));

Then you can use it like below.

On an unrelated note, I've also modified your approach so that you don't need the modified version of executeSave that takes ...args (I think that's a convoluted way to go about it). You can create functions that use the arguments before you pass them into _executeSafe_:

letgoodFun = (fruit) => `I like ${fruit}`;

letbadFun = (fruit) => {
  throw`${fruit} is spoiled!`;
};

letbadPromise = (fruit) => Promise.reject(`Promise failed with ${fruit}`);

letgoodPromise = (fruit) => Promise.resolve(`Promise succeeded with ${fruit}`);

letexecuteSafe = fun => Promise.resolve().then(fun);

functionallSettled(values) {
  letsettle = 
    value => Promise.resolve(value)
      .then(result => ({ state: "fulfilled", value: result }))
      .catch(error => ({ state: "rejected", reason: error }));

  returnPromise.all(values.map(settle));
}

letasyncFun =
  (fruit) =>
    allSettled([badFun, goodFun, badPromise, goodPromise]
      .map(fun =>() =>fun(fruit))
      .map(executeSafe)
    );

asyncFun("orange").then(results =>console.log(results));

Additional side note - if you wanted to use the promisify function from Jared Smith's answer, then you could change your asyncFun function to this:

let asyncFun =
  (fruit) =>
    allSettled([badFun, goodFun, badPromise, goodPromise]
      .map(promisify)
      .map(fun => fun(fruit))
    );

Solution 2:

So this works, catches fine. If the function passed to promisify returns a promise, it just gets passed up the chain.

varfnThatThrows = s => { thrownewError(s) };
varidentity = x => x;

varpromisify = f => (...args) =>newPromise((res, rej) => {
  try {
    res(f(...args));
  } catch (e) {
    rej(e);
  }
});

var rejected = promisify(fnThatThrows);
rejected("foo").then(_ =>console.log("shouldn't see")).catch(e =>console.log(e)); // logs errorvar succeded = promisify(identity);
succeeded("foo").then(val =>console.log(val)); // logs 'foo'

If the promise from the argument function is rejected, that gets passed along too:

varreturnsBadPromise = s => Promise.reject(newError(s));
promisify(returnsBadPromise)("foo").catch(e =>console.log(e)); // logs error

Post a Comment for "Promise Then And Catch Clauses Not Working"