Promise in Javascript 
Tags: javascript, webdev
Published: 2020-07-09 17:59:36

I just wanted to share **what is promise in javascript?**, because I struggled to understand the concept from videos and articles, so I thought of sharing a simple **Promise** object that I have created. I hope you guys will have better understanding after going through this article. 

##Prerequisite:
Before getting started, you should have basic understanding of **OOJS**, **callback** functions and **prototype** methods.

##Callback Function:
`Callback` function is a function which are being passed into another function as a **reference** and got executed there. Have a look at the example below to have a better understanding.

###Code
```javascript
function A(callback) {
    //Call function B
    callback();
}

function B() {
    console.log('Function B got Executed');
}

//Calling the function A with function B as parameter
A(B);

```

###Console
```
Function B got executed
```
The above code will output "Function B got executed" in console, since we are passing the reference of function `B` to function `A` as parameter. Function `B` are called back inside the function `A`. That's why it's called as **callback** function.

##Promises:
Simply, Promises will always come back with a **status**, no matter what happens. 

It's like give me the task, I will definitely tell you whether the task has **completed** or **not** in future period. And also it'll give the **result** or **error** along with the status.

Let's say you're fetching a resource from a website using your program, 
  1. You will make a request to the website,
  2. Website may respond to your request with a **success** response or an **error** response.
     * If success means - You will get the desired resource as response.
     * If Error means - You will get an error as response. I have an ultra slow network connection, so I often receive `connection timed out` as response.

###Code
```javascript
function temp() {
  //Fetch will return a promise
  let promise = fetch('https://jsonplaceholder.typicode.com/users');
  console.log(promise);
}

//Call temp function
temp();
``` 
**(Don't worry about fetch api right now)**

**Fetching from Website**:
I am using fetch API to make a request to the URL https://jsonplaceholder.typicode.com/users to get users data inside `temp` function - `let promise = fetch('https://jsonplaceholder.typicode.com/users')`.

   * If success means - fetch will return a `Promise` object with `status`: `resolved` and `value`: `Response` object. 

     **Note:** `status` property of `Response` object will be `status`: `200`. Success means - You will have the desired **resource** inside the `Response` object.
```
>Promise {<pending>}
  >__proto__: Promise
   [[PromiseStatus]]: "resolved"
  >[[PromiseValue]]: Response
     body: (...)
     bodyUsed: false
    >headers: Headers {}
     ok: true
     redirected: false
     status: 200
     statusText: ""
     type: "cors"
     url: "https://jsonplaceholder.typicode.com/users"
    >__proto__: Response
```

   * If Error means - fetch will return a `Promise` object with `status`: `resolved` and `value`: `response` object.

     **Note:** `status` property of `Response` object will be `status`: `404`. Error means - You will get an `error` response.

     Here, I used invalid URL `https://jsonplaceholder.typicode.com/use`, so I am getting `404` `status`
```
>Promise {<pending>}
 >__proto__: Promise
  [[PromiseStatus]]: "resolved"
 >[[PromiseValue]]: Response
    body: (...)
    bodyUsed: false
   >headers: Headers {}
    ok: false
    redirected: false
    status: 404
    statusText: ""
    type: "cors"
    url: "https://jsonplaceholder.typicode.com/use"
   >__proto__: Response
```

**Accessing the resource**:
  * To access the success `Response` from `Promise` object, we have to call `then` method with the `Promise` instance - "promise". 
  * For accessing error `Response`, `catch` method is used to capture the error response.

```javascript
function temp() {
  //Fetch will return a promise
  let promise = fetch('https://jsonplaceholder.typicode.com/users');
  
  //accessing the response using then()
  promise.then(function(res) {
    return res.json();
  })
  .then(function(json){
    console.log(json);
  })
}

temp();
```
Here, We are getting the `Response` by calling `then` method on `Promise` instance - "promise", `then` method accept an anonymous function as argument. 
  If you put this line inside `temp` function - `promise.then((res) => {console.log(res)})`, you will get the `Response` object as below:

```
>Response {type: "cors", url: "https://jsonplaceholder.typicode.com/users", redirected: false, status: 200, ok: true, …}
```

In first `then` method, we are returning `res.json()`, `json` method will return another `Promise` object. 
     If you put this line inside `temp` function- `promise.then((res) => {console.log(res.json())})`, you will get a `Promise` object as below:

```
>Promise {<pending>}
  >__proto__: Promise
    [[PromiseStatus]]: "resolved"
   >[[PromiseValue]]: Array(10)
```
Second `then` method is used again to capture the `Response` object from `Promise` object returned from `res.json()`. 

     Now, you will get `Array` of 10 users in console as below:

```
10) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
0: {id: 1, name: "Leanne Graham", username: "Bret", email: "Sincere@april.biz", address: {…}, …}
1: {id: 2, name: "Ervin Howell", username: "Antonette", email: "Shanna@melissa.tv", address: {…}, …}
2: {id: 3, name: "Clementine Bauch", username: "Samantha", email: "Nathan@yesenia.net", address: {…}, …}
3: {id: 4, name: "Patricia Lebsack", username: "Karianne", email: "Julianne.OConner@kory.org", address: {…}, …}
4: {id: 5, name: "Chelsey Dietrich", username: "Kamren", email: "Lucio_Hettinger@annie.ca", address: {…}, …}
5: {id: 6, name: "Mrs. Dennis Schulist", username: "Leopoldo_Corkery", email: "Karley_Dach@jasper.info", address: {…}, …}
6: {id: 7, name: "Kurtis Weissnat", username: "Elwyn.Skiles", email: "Telly.Hoeger@billy.biz", address: {…}, …}
7: {id: 8, name: "Nicholas Runolfsdottir V", username: "Maxime_Nienow", email: "Sherwood@rosamond.me", address: {…}, …}
8: {id: 9, name: "Glenna Reichert", username: "Delphine", email: "Chaim_McDermott@dana.io", address: {…}, …}
9: {id: 10, name: "Clementina DuBuque", username: "Moriah.Stanton", email: "Rey.Padberg@karina.biz", address: {…}, …}
length: 10
__proto__: Array(0)
```

##Using Javascript Promise Object;
Instead of getting the `Promise` object from **Fetch API**, we can define our own `Promise` object:

```javascript
const promise = new Promise(function(resolve, reject) {
  const success = true;
  if(success) {
    resolve('Content Loaded');
  } else {
    reject('Some error occurred');
  }
});

promise
.then(function(success){
  console.log(success);
})
.catch(function(error) {
  console.log(error);
})
```
**Instantiating Promise Object**:
   Here, I am instantiating new `Promise` object and stored it in a variable called `promise`. 

   * The `Promise` object accept an anonymous function as an argument, the anonymous itself accept two callback functions as arguments. 

   * Inside the anonymous function, we are calling the corresponding callback function based on the conditional inside the anonymous function.
     * **Conditions**:
        * `if(success)` evaluates to `true` -> call `resolve('Content Loaded')` - resolve callback function will be called.
        * `else` -> call `reject('Some error occurred')` - `reject` **callback** function will be called.

     * Since, the `success` variable set to `true`, the `if` statement will always evaluates to `true`, so the `resolve` function will be called.

     Now, the `promise` variable will have a `Promise` object with status as "resolved" and response as "Content Loaded" as below:
```
>Promise {<resolved>: "Content Loaded"}
  >__proto__: Promise
    [[PromiseStatus]]: "resolved"
   >[[PromiseValue]]: "Content Loaded"
```
**Try** - `console.log(promise)`, you will get an output like above in console.


**Capturing the response**:
   * The **response** can be captured by calling `then` method on `Promise` instance - "promise" by passing an `anoynmous` function with an argument(`success`) to capture the value "Content Loaded" in variable `success`.(`success` will have a `string` - `Content Loaded`).
####Output:
```
Content Loaded
``` 
  * **Try** - changing the `success` variable inside the `Promise` object anonymous function to `false` like `const success = false`, as a result:
    * `else` block will be executed during instantiation, which inturn will call the `reject` callback function, which can be captured using `catch` method on `Promise` instance - "promise".

####Change success variable: `const success = false`
```
Some error occurred
```
**Note**: Calling the `reject('Some error occurred')`, will give us a `Promise` object - which will have status as "rejected" and value as "Some error occurred":

####Reject Promise object:
```
Promise {<rejected>: "Some error occurred"}
__proto__: Promise
[[PromiseStatus]]: "rejected"
[[PromiseValue]]: "Some error occurred"
```

##Summary of Promise:
  * `Promise` object has three states(status):
    * **resolved** - If the request is fullfilled, you will get a `Promise` object with status "resolved".
    * **rejected** - If the request is not fullfilled, you will get a `Promise` object with status "rejected".
    * **pending** - If the request is in intermediate state, you will get a `Promise` object with status "pending" and value "undefined". 
        **Try**:`console.log(new Promise(() => {});`, you will get a `pending` response.

  * `Response` capturing:
    * **resolved** - The `Response` object can be captured using `then` method on `Promise` instance.
    * **rejected** - The `Response` object can be captured using `catch` method on `Promise` instance.
    * **pending** - pending response can't be captured using `then` or `catch` methods. And it's seems reasonable, because we don't need a pending response, because it will not have any data or error.


##Creating Look-alike Promise Object:
Now, we know **what is promise?**, let's define our own `Promise` object `DoYouLearnProgramming`:

###Defining DoYouLearnProgramming Object:
```javascript
function DoYouLearnProgramming(programming) {
  let self = this;
  programming(function(msg) {
    self.resolve = msg;
  }, function(msg) {
    self.reject = msg;
  });
}
```
* Here, I am declaring an object `DoYouLearnProgramming` which accept a callback function `programming` as an arugument.

* The callback function - `programming` itself accepts two anonymous function as arguments.

* I am setting the `this.resolve` and `this.reject` property to corresponding `msg` being passed to each anonymous functions.

* And the callback function will be executed during instantiation.


###Defining Prototype method:
```javascript
DoYouLearnProgramming.prototype.then = function(arg) {
  if(this.resolve === undefined) {
    return this;
  } else {
    this.resolve = arg(this.resolve);
    return this;
  }
}

DoYouLearnProgramming.prototype.catch = function(arg) {
  if(this.reject === undefined) {
    return this;
  } else {
    this.reject = arg(this.reject);
    return this;
  }
}
```
* Then, I am defining two prototype functions `then` and `catch`, which also accept an anonymous function as an argument. 

* Some conditionals checks were happening inside the function, which checks `this.resolve` and `this.reject` property value and perform the corresponding operations. 

  * If the condition evaluates to `true`, it will return the object instance itself.
  * If the condition evaluates to `false`, it will set the corresponding property value, by executing the callback function with the corresponding property value passed as argument.


###Instantiating DoYouLearnProgramming Object:
```javascript
let p = new DoYouLearnProgramming(function(success, fail) {
  if(true) {
    success('You will be a developer');
  } else {
    fail('Develop something for you');
  }
});
```

Here, we are instantiating `DoYouLearnProgramming` by passing an anonymous function with two callback function as arguments like "we did with Promise object above", the corresponding callback will be executed based on the conditional.

The above code snippet will execute `success` callback function, which set the `this.resolve` property to "You will be a developer".


###Capturing response
```javascript
p.then(function(msg){
  console.log(msg);
}).catch(function(msg){
  console.log(msg);
})
```

Here, we are capturing the `resolve` value using `then` prototype method of `DoYouLearnProgramming` object, like we did above with `Promise` object.




This is my first article, please provide your **feedbacks** guys. Thank you