Cup and Croissant

LTWCS – Promise In JavaScript

Learn Together With Code Snippets is a series of short articles as well as quick tutorials and reminders. In these series, I want to share some useful and specific code snippets that I learned in my work or daily life. And I want to learn together with you.

In this article, we will focus on the promise in JavaScript.

We know that normal JavaScript code flow is single-threaded and synchronous. However, sometimes (OK, a lot of time) we need to run our code independently from the normal flow and don’t want to wait for it. For example in HTTP requestsdatabase connections and/or queriesfile operations, etc. In these situations, we use promise that is a native feature in JavaScript.

The promise is an object and allows us to execute our codes asynchronously. Let’s create our first promise.

let myPromise = (upperBound = 10) => {
    console.log('myPromise, the first line!');

    return new Promise(
        (resolve, reject) => {
            let randomNumber = Math.floor(Math.random() * Math.floor(upperBound));

            if(randomNumber > (upperBound / 2)) {
                resolve(randomNumber);
            } else {
                reject(randomNumber);
            }
        }
    );
}

console.log('Before calling myPromise!');

myPromise(100).then(
    (randomNumber) => {
        console.log('Resolved! Random number: ' + randomNumber);
    }
).catch(
    (randomNumber) => {
        console.log('Rejected! Random number: ' + randomNumber);
    }
).finally(
    () => {
        console.log('Finished!');
    }
);

console.log('After calling myPromise!');

// OUTPUT:
// Before calling myPromise!
// myPromise, the first line!
// After calling myPromise!
// Resolved! Random number: 89
// Finished!

As we see, we didn’t wait for our promise to finish.

A promise can be in three states:

  • Pending. The status that our operation(s) is in execution.
  • Fulfilled. The status that our operation(s) has been executed and became successful.
  • Rejected. The status that our operation(s) has been executed and failed.

In our first example, we handle fulfilled and rejected statuses by ‘.then(…’ and ‘.catch(…’ respectively.

JavaScript allows us to create and control multiple promises.

let myPromise1 = new Promise(
    (resolve, reject) => {
        let randomNumber = Math.floor(Math.random() * Math.floor(100));

        if(randomNumber > (100 / 2)) {
            resolve('myPromise1: ' + randomNumber);
        } else {
            reject('myPromise1: ' + randomNumber);
        }
    }
);

let myPromise2 = new Promise(
    (resolve, reject) => {
        let randomNumber = Math.floor(Math.random() * Math.floor(100));

        if(randomNumber > (100 / 2)) {
            resolve('myPromise2: ' + randomNumber);
        } else {
            reject('myPromise2: ' + randomNumber);
        }
    }
);

let myPromise3 = new Promise(
    (resolve, reject) => {
        let randomNumber = Math.floor(Math.random() * Math.floor(100));

        if(randomNumber > (100 / 2)) {
            resolve('myPromise3: ' + randomNumber);
        } else {
            reject('myPromise3: ' + randomNumber);
        }
    }
);

Promise.allSettled([myPromise1, myPromise2, myPromise3]).then(
    (randomNumbers) => {
        randomNumbers.forEach(
            (item) => {
                console.log(item);
            }
        );
    }
).catch(
    (randomNumbers) => {
        randomNumbers.forEach(
            (item) => {
                console.log(item);
            }
        );
    }
).finally(
    () => {
        console.log('Finished!');
    }
);

// OUTPUT:
// { status: 'rejected', reason: 'myPromise1: 40' }
// { status: 'fulfilled', value: 'myPromise2: 89' }
// { status: 'rejected', reason: 'myPromise3: 44' }
// Finished!

The ‘.allSettled(…’ executes all our promises and waits for all of them to finish then gives us result value or failure reason.

Other running multiple promises and controlling way.

let myPromise1 = new Promise(
    (resolve, reject) => {
        let randomNumber = Math.floor(Math.random() * Math.floor(100));

        if(randomNumber > (100 / 2)) {
            resolve('myPromise1: ' + randomNumber);
        } else {
            reject('myPromise1: ' + randomNumber);
        }
    }
);

let myPromise2 = new Promise(
    (resolve, reject) => {
        let randomNumber = Math.floor(Math.random() * Math.floor(100));

        if(randomNumber > (100 / 2)) {
            resolve('myPromise2: ' + randomNumber);
        } else {
            reject('myPromise2: ' + randomNumber);
        }
    }
);

let myPromise3 = new Promise(
    (resolve, reject) => {
        let randomNumber = Math.floor(Math.random() * Math.floor(100));

        if(randomNumber > (100 / 2)) {
            resolve('myPromise3: ' + randomNumber);
        } else {
            reject('myPromise3: ' + randomNumber);
        }
    }
);

Promise.all([myPromise1, myPromise2, myPromise3]).then(
    (randomNumber) => {
        console.log('Resolved! Random number(s): ' + randomNumber);
    }
).catch(
    (randomNumber) => {
        console.log('Rejected! Random number(s): ' + randomNumber);
    }
).finally(
    () => {
        console.log('Finished!');
    }
);

// OUTPUT 1:
// Rejected! Random number(s): myPromise2: 17
// Finished!

// OUTPUT 2:
// Resolved! Random number(s): myPromise1: 77,myPromise2: 55,myPromise3: 80
// Finished!

‘.all(…’ fulfilled iff all the promises fulfilled. Or rejected iff any of the promises rejected.

If we want to wait for only one promise but don’t know which one is will be finished first. And here the ‘.race(…’.

let myPromise1 = new Promise(
    (resolve, reject) => {
        let randomNumber = Math.floor(Math.random() * Math.floor(100));

        if(randomNumber > (100 / 2)) {
            resolve('myPromise1: ' + randomNumber);
        } else {
            reject('myPromise1: ' + randomNumber);
        }
    }
);

let myPromise2 = new Promise(
    (resolve, reject) => {
        let randomNumber = Math.floor(Math.random() * Math.floor(100));

        if(randomNumber > (100 / 2)) {
            resolve('myPromise2: ' + randomNumber);
        } else {
            reject('myPromise2: ' + randomNumber);
        }
    }
);

let myPromise3 = new Promise(
    (resolve, reject) => {
        let randomNumber = Math.floor(Math.random() * Math.floor(100));

        if(randomNumber > (100 / 2)) {
            resolve('myPromise3: ' + randomNumber);
        } else {
            reject('myPromise3: ' + randomNumber);
        }
    }
);

Promise.race([myPromise1, myPromise2, myPromise3]).then(
    (randomNumber) => {
        console.log('Resolved! Random number(s): ' + randomNumber);
    }
).catch(
    (randomNumber) => {
        console.log('Rejected! Random number(s): ' + randomNumber);
    }
).finally(
    () => {
        console.log('Finished!');
    }
);

// OUTPUT:
// Resolved! Random number(s): myPromise1: 59
// Finished!

Like its name, the promises are in a race. It doesn’t matter a fulfilled or rejected situation. The execution finishes iff any of the promise execution finishes.

Thank you for joining me and learning together. See you next time. I will be here.