In the last year two additional factors encouraged me to change my mind.
- Promises are now native to all modern browsers (and node).
Last week I had a problem where promise rejection deep with a promise stack were going to window.onerror rather than passing up the line. A friend and I spent a couple of hours on understanding promises better. Here are some of our findings.
Basic Promises look like callbacks
In the example above, using the setTimeout callback would produce less code with only a little loss of clarity..
Life gets more interesting when you need a sequence of asynchronous expressions to occur in order where each event requires information from a previous event. In other words, making asynchronous code synchronous.
This is called “callback hell” because each callback is inside the one before causing an unreadable level of indented code.
Now picture the above with code that actually does something. As clear as mud?
Promises can stack as well as chain
If the code passed to a then returns a promise, this is added to the promise chain as you see above. There is nothing stopping the returned promise to be a chain – and so on to any depth. It may not seem much of a difference, but is critical to flow control. In a more complex async interaction, promises from otherwise unconnected functions need to be called in a controlled way.
Then and Catch always return a promise
It doesn’t matter what you return from a then clause – it will always be wrapped in a promise. On consideration, this is obvious. Since then is only called once a promise is fulfilled it only has the option of returning a promise.
This is useful for caching. The first call is asynchronous – loading data from the server. All later calls read from the cache and can return the results immediately.
Exceptions in a promise turn into rejection
The reject function is tightly coupled to the promise. In practice the asynchronous action may be levels need in the call stack. Do we need to pass the reject function down to everyone who may need it. This is not viable if you are using libraries you did not write. Fortunately the designers of Promise-A+ accounted for this. Inside a promise an exception thrown is limited to the promise context and is converted into a call to reject. So, throw away.
There is a caveat. If you have a call-back inside a promise, any exceptions thrown inside the callback is in a different context. They are not converted to promise rejections. This is the only time you will need try and catch.