Also, if you are using frameworks like Angular, React, Ember or other, you will or have already encountered some variations of Promise implementation.
Please note our goal is to understand the concept from “First Principle” and we are not aiming to write production code, but then we will try to follow as much better practices as possible as long as I can keep the explanation simple.
Feel free to share your thoughts, suggestions, edits, tips in the comment section, or alternative implementation that will clear up the concepts.
What is a Promise?
Primarily a Promise object represents the eventual completion or failure of an asynchronous operation and kind-of helps avoid the callback hell (though the primary purpose is not to solve the problem of callback hell).
In short a Promise is a guarantee that on execution of some asynchronous task, the completion status or the rejection status or the errors, if any will be communicated to the calling program in a guaranteed way.
Also one side benefit is Promise make asynchronous code look like sequential code.
Without promise our asynchronous code may look like the below figure. The image is adapted from google images (SO).
There are various Promise library and one of the widely used one is rsvp.js available at https://github.com/tildeio/rsvp.js/.
In our implementation we will stick to two approaches for designing the API. We will not implement all the features but the most important one, then resolve and reject method, with a bit of error handling.
Let’s take an API first approach to design our library. Also please go through the code comments, as I don’t want to repeat things in the article what can be clearly conveyed in the code.
Let’s build a simple HTML markup with a button. On click of the button, we need to execute a long running task. In this case we will not make any real AJAX calls, but will use setTimeout for our purpose.
Assume we have a long running task that has to be executed and resolved at two places in this small app. This is just for demo, we can resolve as many times as required.
- While Initial Load
- On click of the button
Let’s wrap the actual work to be executed in the below method. In the app.js (or any other file) put the below code.
In reality, inside this doLongRunningTask(), we can execute any function, ajax calls etc.
Here’ we are defining our API. We have a MyPromise constructor function (which we haven’t implemented yet, but will shortly).
To simulate long running task we are using setTimeout. In the above case, after 3 seconds the setTimeout will get executed and we will call the resolve() method of our promise object to indicate to the calling function/client that the work is completed.
To execute this function we will invoke it.
At this point our API is slowly evolving. The doLongRunningTask() should return our MyPromise object. We can subscribe to get notified on the task completion by calling the “then” method.
Note here that we can chain the method calls and we can also subscribe multiple times.
Also, if any error happens in the execution, we have the catch method as well.
Additionally, we also want to get notified when the action is completed on button click as well. Note here that the act of clicking the button, the the promise resolution may not happen at the same time.
It may also happen that when the button is clicked the promise is already resolved, as we started the work on page load itself. In that case, the then() method should be immediately executed.
So, far we have developed our API usage pattern, now lets look at the actual implementation of MyPromise, constructor function.
Lets begin with the constructor function. The code is well commented. I am sticking to ES5 (and not using modern ES6 features). The constructor function is invoked by the client by using new MyPromise() as demonstrated earlier.
In case you are creating the promise code in a separate file like “MyPromise.js”, make sure you include it in your HTML file.
Now, to register success callback, let us implement the then() method. As we can chain the then() method, we have to return “this” as part of return value of the function. Here’s the code snippet.
Now, here comes the resolve() method. This is where the callback will be invoked with the returned data.
Let’s now define a simple catch function to handle error. This is the smallest function.
And finally the reject() method, which will use the error callback to raise error to the calling client.
And lo behold, we have completed our first implementation of our own mini Promise library.
Just to show you the usage, we can also use the below native like API for our promise library.
You will observe here that the almost all the API is same , except the way the promise is created.
Lets’ look at the constructor function.
Here’ the important thing is in the constructor function the callback is executed with the context set to the correct instance. Rest of the code is exactly same as our earlier Promise implementation.
Hope you enjoyed reading this as much as I have enjoyed writing it.
If you like articles on similar concepts, feel free to share your thoughts in the comments. Please note, I may have omitted some better practices, error handling for brevity sake.
This is a quick write. In case you need more explanation or clarification, drop me a message in the comment. I will update the story.
The full source code can be found here at jsbin.
Thanks for your time. Cheers and “I Promise to post more similar stories in case you like this !!!”