This article has kindly been turned into a video by the folks at Webucator who do JavaScript training.

When dealing with asynchronous code, JavaScript’s ES6 promises can make your life a lot easier. No more callback pyramids, no more error handling on every second line, and no more reliance on external libraries to do things as simple as getting the result of a for loop.

But ES6 Promises can have their own pitfalls, the biggest by far being disappearing error messages. Reddit’s /u/ledp put it better than I ever could:

What the actual flying fuck? Promises swallows errors by default! Who’s idea was that?

More specifically, any exception which is thrown within a then handler, a catch handler, or within the function passed to new Promise , will be silently disposed of unless manually handled.

The problem

Let’s test your understanding. Which of the following would you expect to print an error to the console?

Promise.resolve('promised value').then(function() { throw new Error('error'); }); Promise.reject('error value').catch(function() { throw new Error('error'); }); new Promise(function(resolve, reject) { throw new Error('error'); });

I don’t know about you, but my answer is that I’d expect all of them to print an error. However, the reality is that a number of modern JavaScript environments won’t print errors for any of them.

Manually regurgitating your errors

The obvious way to go about fixing this is to add an extra catch statement to the end of each of your promise chains. For example, you could fix the first example above with:

Promise.resolve('promised value').then(function() { throw new Error('error'); }).catch(function(error) { console.error(error.stack); });

But are you seriously going to have the self-control to type that out after every then call? I sure don’t. Knowing this, some fine people invented the done method, which is functionally equivalent to the above, and can be used just like then , allowing you to write:

Promise.resolve('promised value').done(function() { throw new Error('error'); });

Meanwhile, back in the real world…

This seems great in theory, taking no more effort than using good ol’ then . But in reality, you generally don’t just use then once, you’ll chain it multiple times. For example, I have a project which grabs data via HTTP, and then further processes the response data asynchronously. Using done , the code would look something like:

getSomethingViaHttp() .then(function(result) { // processResultAsync returns another promise return processResultAsync(result); }) .done(function(processed) { showResult(processed); });

But then what happens when my processing library’s API changes at a later date to be synchronous? I might update the code to the following:

getSomethingViaHttp() .then(function(result) { // processResultAsync returns another promise showResult(processResultSync(result)); });

Oops! I removed the done block, but then forget to swap out the preceding then with a done . The result? I ended up spending hours trying to figure out why my app was silently failing when the HTTP server decided it didn’t like me. True Story!

Tell the computer which errors to discard, not which ones to handle

The problem with being human is that if you can make a mistake, at some point you will. Keeping this in mind, it seems obvious that we should design things in such a way that mistakes hurt as little as possible, and that means handling errors by default, not discarding them.

Happily, there is a library which makes this easy! Bluebird provides a simple fix which easily integrates with your existing code by extending the ES6 Promises API.

After installing bluebird, you can make sure you know about unhandled rejections by adding the following three lines:

Promise.onPossiblyUnhandledRejection(function(error){ throw error; });

And on the odd chance you do want to discard a rejection, just handle it with an empty catch , like so:

Promise.reject('error value').catch(function() {});

And that is all you need to know to promise safely. Of course, promising safely is only the start of doing it well! And promises are only one of many tools in the skilled JavaScript developer’s toolbox.

So if you value your time and want to create Single Page Applications which people love, subscribe to my newsletter! In return for your e-mail, you’ll also immediately receive 3 bonus print-optimised PDF cheatsheets – on ES6, JavaScript promises and React.