The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
-MDN
Put simply[1], it is a means to reorganize asynchronous (concurrently executing) code to reduce nesting among other reasons.
Over the next couple of posts, I'm going to give a brief primer on what a promise is and how to use it but the main purpose of this article is to understand how a Promise library is implemented. I was poking through the source code of Pinkie not too long ago and it seemed like a great article candidate.
Why use one?
Without going into too much detail, they are used to avoid "Callback Hell" as well as create a more familiar code-flow (the try/catch
). pattern. Here's a contrived but pseudo real-world example:
A promise allows us to restructure the code as such as this:
There appears to be more code in the later version because, I suppose, there is. The use of a promise doesn't reduce code. It makes the flow more obvious. And I do believe that is achieved here. You now see the order of execution more clearly. Each then
statement must be completed before the previous then
statement and should an error occur, the catch(function(er){})
will intercede to allow you to handle the error gracefully.
More examples
Promises in JavaScript has become quite ubiquitous. Should you want to see more examples or practical uses of Promises, the pg-promise library has excellent up-to-date examples that are both clear and real-world. The library itself is a PostgreSQL interface for Node.
Next
In the next post, we'll look at how promise libraries are implemented by dissecting the implementation by Floatdrop called Pinkie. A small ES2015 Promise implementation.
An Oversimplification but suitable for our purposes. ↩︎