Catching Errors in JavaScript Promises with a First Level try ... catch

Javascriptnode.jsPromiseBluebird

Javascript Problem Overview


So, I want my first level catch to be the one that handles the error. Is there anyway to propagate my error up to that first catch?

Reference code, not working (yet):

Promise = require('./framework/libraries/bluebird.js');

function promise() {
	var promise = new Promise(function(resolve, reject) {
		throw('Oh no!');
	});

	promise.catch(function(error) {
		throw(error);
	});
}

try {	
	promise();
}
// I WANT THIS CATCH TO CATCH THE ERROR THROWN IN THE PROMISE
catch(error) {
	console.log('Caught!', error);
}

Javascript Solutions


Solution 1 - Javascript

You cannot use try-catch statements to handle exceptions thrown asynchronously, as the function has "returned" before any exception is thrown. You should instead use the promise.then and promise.catch methods, which represent the asynchronous equivalent of the try-catch statement. (Or use the async/await syntax noted in @Edo's answer.)

What you need to do is to return the promise, then chain another .catch to it:

function promise() {
    var promise = new Promise(function(resolve, reject) {
        throw('Oh no!');
    });

    return promise.catch(function(error) {
        throw(error);
    });
}

promise().catch(function(error) {
    console.log('Caught!', error);
});

Promises are chainable, so if a promise rethrows an error, it will be delegated down to the next .catch.

By the way, you don't need to use parentheses around throw statements (throw a is the same as throw(a)).

Solution 2 - Javascript

With the new async/await syntax you can achieve this. Please note that at the moment of writing this is not supported by all browsers, you probably need to transpile your code with babel (or something similar).

// Because of the "async" keyword here, calling getSomeValue()
// will return a promise.
async function getSomeValue() {
  if (somethingIsNotOk) {
    throw new Error('uh oh');
  } else {
    return 'Yay!';
  }
}

async function() {
  try {
    // "await" will wait for the promise to resolve or reject
    // if it rejects, an error will be thrown, which you can
    // catch with a regular try/catch block
    const someValue = await getSomeValue();
    doSomethingWith(someValue);
  } catch (error) {
    console.error(error);
  }
}

Solution 3 - Javascript

No! That's completely impossible, as promises are inherently asynchronous. The try-catch clause will have finished execution when the exception is thrown (and time travel still will not have been invented).

Instead, return promises from all your functions, and hook an error handler on them.

Solution 4 - Javascript

I often find the need to ensure a Promise is returned and almost as often needing to handle a local error and then optionally rethrow it.

function doSomeWork() {
  return Promise.try(function() {

    return request.get(url).then(function(response) {
      // ... do some specific work
    });

  }).catch(function(err) {
    console.log("Some specific work failed", err);
    throw err; // IMPORTANT! throw unless you intend to suppress the error
  });
}

The benefit of this technique (Promise.try/catch) is that you start/ensure a Promise chain without the resolve/reject requirement which can easily be missed and create a debugging nightmare.

Solution 5 - Javascript

To expand on edo's answer, if you want to catch the errors of an async function that you don't want to wait for. You can add an await statement at the end of your function.

(async function() {
  try {
    const asyncResult = someAsyncAction();

    // "await" will wait for the promise to resolve or reject
    // if it rejects, an error will be thrown, which you can
    // catch with a regular try/catch block
    const someValue = await getSomeValue();
    doSomethingWith(someValue);

    await asyncResult;
  } catch (error) {
    console.error(error);
  }
})();

If someAsyncAction fails the catch statement will handle it.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKirk OuimetView Question on Stackoverflow
Solution 1 - JavascriptQantas 94 HeavyView Answer on Stackoverflow
Solution 2 - JavascriptEdoView Answer on Stackoverflow
Solution 3 - JavascriptBergiView Answer on Stackoverflow
Solution 4 - JavascriptkingdangoView Answer on Stackoverflow
Solution 5 - JavascriptJonathan FelchlinView Answer on Stackoverflow