DEV Community

Ayanabilothman
Ayanabilothman

Posted on

JavaScript promises are simple πŸ‘Œ

This article will be simple and only mentions basics related to promises in JavaScript and why we need them. Be ready and just read this story and enjoy understanding promises. πŸ€—.

πŸ‘€Important to know that:

JavaScript is a non-blocking language. What does this mean? When JavaScript engine starts to run the code, it doesn't implement the statements in the order as you write them πŸ€” "in some cases". So let's see how can this look like.

Image description

πŸ‘‰πŸΌ After executing the above code the result will be:
I'm the first statement
I'm the third statement
I'm the second statement

And the reason behind this behavior is the usage of setTimeout function which is an asynchronous function in JavaScript.
So, what is asynchronous function? πŸ€”

Simply, it's a function that may take some time. Thus, JavaScript engine holds the execution of it and runs the rest of the code. After finishing all non-asynchronous statements, it finally executes this postponed asynchronous function.

This is the exact meaning of non-blocking language, this behavior of holding on the execution of some code written at certain order and be able to execute it later.

Problem definitionπŸ˜“:

Why this non-blocking behavior can be an issue in some cases? What if you need to do some operations ("b" & "c") which depends on another operation "a" that can take some time? πŸ‘‡

Now let me introduce an interesting case study πŸ€“.

We need to fetch a video from a database, but this operation can take some time due to internet connection or for any other reasons. After receiving the video, we need to trim it. The last thing we need is to display the trimmed video.

So now we have three operations:
a- Request the database to fetch the video.
b- Trim the received video.
c- Display the trimmed video.

As you see, the three operations depend on each other, you can't trim or display the video until you receive the original one.

Let's define the functions to do each single operation:

Image description

Hint: we use setTimeout function inside fetchDB function to just simulate as if we are fetching data from a database.

It is time to execute these operations:

Image description

πŸ‘‰πŸΌ After executing the above code the result will be:
undefined After trim. And here is the final video to display!

Notice that the first word is "undefined". This value is the result of invoked fetchDB function in statement number 20. But why it is "undefined"? because of the same reason fetchDB function has setTimeout function which will take some time. So the engine skips it and in turns it will return nothing, so the value will be undefined.

Since all other functions trimVideo and displayVideodepend on the original video so they won't return the expected result.

What is the solution then?

Solution 1 πŸ™Œ: Callback functions

To handle this, we can use callback functions. What is a callback function? It's a function that is a parameter of another function.

Image description

fn_1 is a simple regular function. What if it takes a parameter? this parameter can be of any type even if it was a function.
How can you invoke fn_1 function? You need to pass the function as an argument.

Image description

πŸ‘‰πŸΌ After executing the above code the result will be:
f1
f2

So now returning to our case, how you use callback functions to successfully execute all operations related to the required video?

The trimVideo function relies on the fetchDB function. We can rewrite fetchDB function to take function as an argument (callback function) which will be the trimVideo function.

Image description

In addition, the displayVideo function relies on the trimVideo function.Thus, you can rewrite trimVideo function to take function as an argument (callback function) which will be the displayVideo function.

Image description

The displayVideo function will still the same as it is the final operation and there is no more operations depends on it.

Image description

Now how can we redefine the main function?

Image description

πŸ‘‰πŸΌ After executing the above code the result will be:
Here is the video. After trim. And here is the final video to display!

Finally, we got the expected results. But it seems that this is a complex code, doesn't it? What we did here is when we invoke the functions, each function that takes callback function added complexity to the code. And this is known as callback hell.Β Writing nested callback functions is so hard and complex.
More details on callback hell can be found here.

Are there any alternative solutions to avoid using callback functions and simplify the code writing? Yes, thanks to ES6.

Solution 2 πŸ™Œ: Promises

I know you read a lot to reach here, but the reason behind using promises will help you well understand why promises are so valuable.

What is a promise? Promise is a special object in JavaScript, it has two main attributes or properties (state + result) (Remember this for later discussion) . Let's dive deep and enjoy coding with promises.

Image description

As shown in the above code, to construct a promise you need to create an instance object from a predefined class Promise using new keyword. Writing new Promise() will create a promise object. But what is the function inside those round brackets?

(resolve, reject)=>{} is a function which has two arguments (resolve, reject), you can rename them anything else, but by convention they're called resolve and reject.

And now what are those resolve and reject? πŸ€” They are two callback functions "but don't worry we won't write here anymore callback functionsπŸ˜…. We just need to understand what we write while constructing a promise". As you knew before, when you write a function as an argument you can call this function whenever you want inside the parent function.

And this exactly what happens. When should you call these functions?

  • you should invoke the resolve function when you need to return a value if your code has executed in an expected manner.

  • Otherwise, you should invoke the reject function to return a value if your code failed or an error occurred.

Knowing that, only one function got invoked. If you try to invoke both functions after each other without any conditions. Only the first one will be invoked either it was the resolve function or the reject function.

Image description

At the beginning of this section, we say that promise has two main attributes or properties** (state + result)**.

Simply the state can be one of three states:

  • pending
  • fulfilled
  • rejected

While the result is any value of any type which you pass to the resolve or the reject functions when you invoke them.

Results depend on the states. if the state was fulfilled, resolve function get invoked with the result. And when the state was rejected, reject function get invoked with the result.

But _what is a pending state? πŸ€” It is the state of the promise which hasn’t been fulfilled nor rejected yet. This state has no results you can deal with.

Ok, you now understand what is promise. The final question, how can it help you?

Any promise object has then property. then is just a function that takes another function as an argument.

Image description

The interesting here, that the arguments of this callback function is the result you previously sent through resolve function.

Image description

In addition, any promise object has catch property. catch is just a function that takes another function as an argument.

Image description

The interesting here as well, that the arguments of this callback function is the result you previously sent through reject function.

Image description

then and catch will never get invoked until the promise is fulfilled or rejected meaning that the resolve or the reject function must be invoked.

The last thing you need to know is that then function returns implicit promise by default. Implicit promise is a promise you didn't completely write, when you return any value 'X' from the callback function of then function, this value 'X' acts as a resolved result from a hidden resolve function. Thus, you can write a chain of then functions.

Image description

Returning to our problem, how can we use promises to handle our situation?

JavaScript engine deals with this chain of then functions as one unit and doesn't execute any of them until the previous then function resolved. Which means that any code written inside this chain will be executed in the right order as you write and this is what we need.
In addition, the engine will execute those functions in asynchronous way. It won't block any code after then functions.

Image description

πŸ‘‰πŸΌ After executing the above code the result will be:
First statement out of promise
Second statement out of promise
4

Applying these concepts in our operations we can rewrite our code as the following πŸ‘‡:

Image description

The difference between writing the code using promises and writing the code using the callback functions is so obvious. The code is more clear, simple and understandable now πŸ₯³.

We can enhance the writing of promises and chains in some cases using async/await keywords. πŸ‘‰ Write promises chaining using async/await πŸ‘ˆ article will clarify the idea 😊.

Error handling of promises is a great topic. It will be clarified in another article, just wait for it πŸ”₯.

Top comments (3)

Collapse
 
mahmoud59576620 profile image
mahmoud ahmed

Awesome

Collapse
 
alaagamalabdelhameed profile image
alaagamalabdelhameed

Amazing

Collapse
 
develekko profile image
Housam Ramadan

Awesome