DEV Community

Cover image for JS Promises Simplified!!!
Tanmay Agrawal
Tanmay Agrawal

Posted on

JS Promises Simplified!!!

What are Promises ?

promises are objects that represent the eventual completion or failure of an async task!!.
(Assume the Promise is just as "Promise" from plain English language.).

"😎 JavaScript promises are more reliable than the promises that your partner made"

When you create a promise, it will be in one of the following states:

  1. Pending: The initial state of the Promise before it is fulfilled or rejected.
  2. Fulfilled: The state of the Promise representing a successful operation.
  3. Rejected: The state of the Promise representing a failed operation

If your partner promises you that "we will be together"💕 consider this as a Pending promise🤞, However he/she dumps💩 you then consider it as Rejected promise😭. But if he/she was a green flag and finally you both get married💑 then it is a Fulfilled promise😎.

You can create new promise using the Promise constructor, and you can attach callbacks to it using the .then() and .catch() methods to handle the resolved value or the error, respectively.
Here is a syntax to create a promise!! . Try running this code itself

const promise = new Promise((resolve,reject)=>{
//console.log("Try to run me before writing last line see what happens!!")
  resolve("Success!!!")
})

promise.then(data=>console.log(data))
Enter fullscreen mode Exit fullscreen mode

Also, Let me know that if we uncomment the second line, and simply run the code after declaring promise,

Another example with a rejected promise!!!

const promise = new Promise((resolve,reject)=>{

  setTimeout(()=>{

  reject("Failure!!!")
  },3000)
})

promise.then(data=>console.log(data)).catch(err=>console.error(err))
Enter fullscreen mode Exit fullscreen mode

TASK : Can you write a relationship promise ? prompt a question "Do you want to marry me ?" If the user inputs "Yes" then the promise must be fulfilled after- 3 sec. and if user inputs "No" then the promise should rejects! (Challenge :- Try to make it with the DOM Manipulation A Input and Button Ask and reply should be below!!, You can also get creative if you want.)

Advance Concepts of Promises.

There are also some Techniques to optimize the performance. You can try them below
Here's a breakdown of the differences between Promise.all, Promise.allSettled, and Promise.race:

1.Promise.all:

  • It takes an iterable of promises as an input.
  • Resolves when all the promises in the iterable have resolved.
  • If any promise rejects, the entire Promise.all call is rejected immediately with the reason of the first rejected promise.
  • Returns an array of the resolved values in the same order as the input promises.

2.Promise.allSettled:

- It takes an iterable of promises as an input.
- Resolves when all the promises in the iterable have either resolved or rejected.
- It does not short-circuit when a promise rejects, and it waits for all the promises to settle before resolving.
- Returns an array of objects representing the outcome of each promise, including a `status` property indicating whether the promise was fulfilled or rejected, along with a `value` or `reason` property.
Enter fullscreen mode Exit fullscreen mode

3.Promise.race:

- It takes an iterable of promises as an input.
- Resolves or rejects as soon as one of the promises in the iterable resolves or rejects.
- Returns the value or reason from the first settled promise.
- It does not wait for all promises to settle and can be used to implement a timeout feature or race conditions between different asynchronous operations.
Enter fullscreen mode Exit fullscreen mode

These methods provide different ways of handling multiple promises, allowing you to manage asynchronous operations effectively depending on your specific use case.

Promise.all Another Example

let job = (delay)=>{
  return new Promise((resolve)=>{
    setTimeout(()=>{
      console.log("message : "+ delay)
      resolve(delay)
    }, delay)
  })
}

Promise.all([job(5000), job(2000), job(3000)]).then(data=>{ console.log("printing : \n"); data.forEach(item=>console.log(item))}).catch(err=>console.log(err))

//Output : 
//message : 2000
//message : 3000
//message : 5000
//printing :
//5000
//2000
//3000
Enter fullscreen mode Exit fullscreen mode

*Promise.all fails if any one of the promise fails Example : *

let p1 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 500, 'p1');
});

let p2 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 1000, 'p2');
});

let p3 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 1200, 'p3');
});

let p4 = new Promise(function(resolve, reject) {
    setTimeout(reject, 300, 'p4');
});

let p5 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 800, 'p5');
});

let p6 = new Promise((resolve, reject)=>{
  resolve('P6')
})
let promise = Promise.all([p1, p2, p3, p4, p5, p6]);

promise

.then(function(data) {
    data.forEach(function(data) {
        console.log(data);
    });
})

.catch(function(error) {
    console.error('error', error);
});

//Output
//Error: error p4
Enter fullscreen mode Exit fullscreen mode

Now there is one thing can be done in order to avoid short circuiting is. To use promise.allSettled but Then it will log the settled promises as an object.
or Alternatively all promise.all with each catch calls like following

let promise = Promise.all([p1.catch(()=>{}), p2.catch(()=>{}), p3.catch(()=>{}), p4.catch(()=>{}), p5.catch(()=>{}), p6.catch(()=>{})]);

//output
//p1
//p2
//p3
//undefined
//p5
//P6
Enter fullscreen mode Exit fullscreen mode

In the same above example let us use the promise.race

let promise = Promise.race([p1, p2, p3, p4, p5, p6]);
promise
.then(function(data) {
        console.log(data);
})

.catch(function(error) {
    console.error('error', error);
});

//Output
P6
Enter fullscreen mode Exit fullscreen mode

Promise Chaining

consider the following code

var promise = job1();

promise
.then(function(data1) {
    console.log('data1', data1);
    return job2();
})
.then(function(data2) {
    console.log('data2', data2);
    return 'Hello world';
})
.then(function(data3) {
    console.log('data3', data3);
}).then(data=>console.log(data));

function job1() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve('result of job 1');
        }, 1000);
    });
}


function job2() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve('result of job 2');
        }, 1000);
    });
}

///Output
//data1 result of job 1
//data2 result of job 2
//data3 Hello world
//undefined
Enter fullscreen mode Exit fullscreen mode
  • We call job1 and we store the returned promise in a variable called promise.
  • We call then on this promise and we attach a callback for when the promise is resolved
  • We print data1 and it is obvioulsy result of job 1 
  • we call job2 and we return the resulting promise.
  • We call then on the result of the first then. The result of then is always a promise. Always. At worst, it can be a never resolved promise, but it is a promise. In this case, the promise is the return value of job2 . When you are in a then callback, if you return a promise, it will be the resulting promise of the then call.
  • We print data2. According to the resolve call in the promise returned by job2 , data2 is result of job 2 . By chaining our 2 promises (job1 then job2), job2 is always executed after job1.
  • We return a simple string 'Hello world'.
  • We call then on the result of the then call . The promise here is an auto-resolved promise, and it will pass 'Hello world' in the data. When you are in a then callback, if you return anything but a promise, an auto-resolved promise is created, and this promise will be the result of the then call.
  • We print data3 and this is the 'Hello world' will return.

The Broken Chain !

function test() { 
    var promise = job(); 
    promise.then(function(data) { 
        doSomething(data); 
        }); 
    return promise; 
}
Enter fullscreen mode Exit fullscreen mode

In this code the promise.then is not returned, in-fact the function test returns the initial promise. and therefore the result of the promise.then is lost. Because there is no one can interact with it.

How to fix it?

function test() { 
    return job().then(function(data) { 
        doSomething(data); 
        });  
}
Enter fullscreen mode Exit fullscreen mode

Creating auto Resolve and auto Reject promises

function job() { 
    if (test) { 
    return aNewPromise(); 
    } else { 
    return Promise.resolve(42); // return an anto-resolved promise with `42` in  data. 
    } 
}
Enter fullscreen mode Exit fullscreen mode

Promise.resolve(42) Auto-resolve promise
promise.reject('error') Auto reject promise

As a rule of thumb 👍: whenever a function can return a promise, ALWAYS return a promise.

success defeat error Error caught

Test Example to test Chaining with Catch

function job(state) {
    return new Promise(function(resolve, reject) {
        if (state) {
            resolve('success');
        } else {
            reject('error');
        }
    });
}

let promise = job(true);

promise

.then(function(data) {
    console.log(data);

    return job(true);
})

.then(function(data) {
    if (data !== 'victory') {
        throw 'Defeat';
    }

    return job(true);
})

.then(function(data) {
    console.log(data);
})

.catch(function(error) {
    console.log(error);

    return job(false);
})

.then(function(data) {
    console.log(data);

    return job(true);
})

.catch(function(error) {
    console.log(error);

    return 'Error caught';
})

.then(function(data) {
    console.log(data);

    return new Error('test');
})

.then(function(data) {
    console.log('Success:', data.message);
})

.catch(function(data) {
    console.log('Error:', data.message);
});


//Output:
//success, Defeat, error, Error caught, Success: test
Enter fullscreen mode Exit fullscreen mode

So as per my understanding based on the example above. Promise is resolve it goes to the success callback function chained with .then function(). But if promise is rejected and the error is thrown by means of throw new Error or throw Error, Then it is caught by the catch block.
Now if the catch block returns anything, then the chaining continues with the .then callback function but if catch block throws error then it will be caught by the next catch block.
Also if the promise is rejected then the catch block is executed with the error message.

Top comments (1)

Collapse
 
oculus42 profile image
Samuel Rouse

I appreciate the description detail and humor in your article!

I often see Promises with unnecessary wrapper functions, like .then(data=>console.log(data) instead of .then(console.log). While there are cases where wrappers can be necessary, it can be much easier to read when we directly pass named functions.

It's the first of the tips in a post I made last year, if you are interested.