Home

Asynchronous Javascript

Asynchronous - more than one code thread can be run at the same time.
Synchronous - (default) code runs as one thread and one command has to finish before the next one can start.

Constructing a Promise Object

...you can also take a look at an MDN document on Graceful Asynchronous Programming.
...and another document (Understanding JavaScript Promises) can be found Here.

The Promise constructor method takes a function parameter called the executor function which runs automatically when the constructor is called.
The executor function generally starts an asynchronous operation and dictates how the promise should be settled.

To create a new Promise object, we use the new keyword and the Promise constructor method:, eg...

const executorFunction = (resolve, reject) => { };
const myFirstPromise = new Promise(executorFunction);


The executor function has two function parameters, usually referred to as the resolve() and reject() functions.
The resolve() and reject() functions aren’t defined by the programmer.
When the Promise constructor runs, JavaScript will pass its own resolve() and reject() functions into the executor function.

resolve
is a function with one argument. Under the hood, if invoked, resolve() will change the promise’s status from pending to fulfilled, and the promise’s resolved value will be set to the argument passed into resolve().

reject
is a function that takes a reason or error as an argument. Under the hood, if invoked, reject() will change the promise’s status from pending to rejected, and the promise’s rejection reason will be set to the argument passed into reject().

An example of this could be...

const executorFunction = (resolve, reject) => {
   if (someCondition) {
      resolve('I resolved!');
   } else {
      reject('I rejected!');    }
}

const myFirstPromise = new Promise(executorFunction);

Top

I had to create a small working file as part of my Codecademy course.

It is in a file in the /Scripts folder called sunglasses.js, to run it you can open windows command prompt then change directory (cd) in to the folder and then type...
$ node sunglasses.js

The code is also listed below for reference...

const inventory = {
  sunglasses: 1900,
  pants: 1088,
  bags: 1344
};

const myExecutor = (resolve, reject) => {
  if (inventory.sunglasses > 0) {
    resolve("Sunglasses order processed.");
  } else {
    reject("That item is sold out.");
  };
}

const promiseSunglasses = new Promise(myExecutor);

const orderSunglasses = () => {
  return promiseSunglasses;
}

var orderPromise = orderSunglasses();
console.log(orderPromise);


When this is run it should display, in the console.log, the following message...
Promise { 'Sunglasses order processed.' }

Top

Something different I came across

The way you read in (.require) and inherit from a different .js file changes the way you refer to the methods in that file.

For example...

Below are the contents of a file called myLibrary.js...

const inventory = {
  sunglasses: 1900,
  pants: 1088,
  bags: 1344
};

const checkInventory = (order) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      let inStock = order.every(item => 
inventory[item[0]] >= item[1]);
      if (inStock) {
        resolve(`Thank you. Your order was 
successful.`);
      } else {
        reject(`We're sorry. Your order could 
not be completed because some items are sold out.`);
      }
    }, 1000);
  })
};

module.exports = {checkInventory};


There are two ways to .require() the myLibrary.js file in to your main .js file that you want to call the routines from...

First Way
const {checkInventory} = require('./myLibrary.js');

OR...

Second Way
const checkInventory = require('./library.js');

Note...
You use .require() when running thru the command prompt.
And you use import/export (import {method1, method2} from './anotherLibrary.js';) when running on an .html file.
Here I am ONLY talking about using the .require() option.


So when using the FIRST way
const {checkInventory} = require('./myLibrary.js');
you would then call checkInventory() by referring to it as a property (which, I think the {} represents), eg...
checkInventory(order);

Whereas using the SECOND way
const checkInventory = require('./myLibrary.js');
you would then call checkInventory() by referring to the variable name used in the .require() followed by a dot (.) and the actual method name used on the myLibrary.js file, eg...
checkInventory.checkInventory(order);
a little confusing as I called the imported variable the same as the method name in myLibrary.js

See below for the FIRST and the SECOND examples as a file (myApp.js)

Top

Example of myApp.js using the FIRST way

const {checkInventory} = require('./myLibrary.js'); 

const order = [['sunglasses', 1], ['bags', 2]];

const handleSuccess = (resolvedValue) => {
  console.log(resolvedValue);
};
 
const handleFailure = (rejectionReason) => {
  console.log(rejectionReason);
};

checkInventory(order).then(handleSuccess, 
handleFailure); 
//will print on the console.log 
//"Thank you. Your order was successful."

Example of myApp.js using the SECOND way

const checkInventory = require('./myLibrary.js'); 

const order = [['sunglasses', 1], ['bags', 2]];

const handleSuccess = (resolvedValue) => {
  console.log(resolvedValue);
};
 
const handleFailure = (rejectionReason) => {
  console.log(rejectionReason);
};

checkInventory.checkInventory(order).then(handleSuccess, 
    handleFailure); 
//will print on the console.log 
//"Thank you. Your order was successful."

Top

The box above uses .then()

.then() is used as part of the 'Success and Failure Callback Functions'
To handle a “successful” promise, or a promise that resolved, we invoke .then() on the promise, passing in a success/failure handler callback function.

The two functions (handleSuccess & handleFailure)) form part of this routine
and the .then() routine uses them, so if the checkInventory() passes or fails then the correct message would get sent to the console log.

You can try this link for a bit more information See Mozilla

Using .catch() with Promises

One way to write cleaner code is to follow a principle called separation of concerns.
Separation of concerns means organizing code into distinct sections each handling a specific task.
It enables us to quickly navigate our code and know where to look if something isn’t working.

To create even more readable code, we can use a different promise function: .catch().
The .catch() function takes only one argument, onRejected. In the case of a rejected promise, this failure handler will be invoked with the reason for rejection.
Using .catch() accomplishes the same thing as using a .then() with only a failure handler.

An example of using .catch() could be...

checkInventory(order)
    .then(handleSuccess)
    .catch(handleFailure);

Because we already created functions handleSuccess & handleFailure to write out to the console.log we only need the above.
But if we did NOT create handleSuccess or handleFailure to do that we would need to create anonymous functions in the .then() and .catch() like so...
checkInventory(order).then((mySuccess) => {
    console.log(mySuccess);
  })
  .catch((myFailure) => {
    console.log(myFailure);
  });

Top

Chaining multiple promises

You can chain multiple promises by using multiple .then() commands, eg...

checkInventory(order)
    .then((resolvedValueArray) => {
      return processPayment(resolvedValueArray);
    })
    .then((resolvedValueArray) => {
      return shipOrder(resolvedValueArray);
    })
    .then((successMessage) => {
      console.log(successMessage);
    })
    .catch((errorMessage) => {
      console.log(errorMessage);
    });

checkInventory is the first task, processPayment is the second and shipOrder is the third task.
If ANY of them fail then the .catch() will happen and show the failed message (which is the rejected reason from whatever failed).


Note
The .then() commands are chained not nested within each other.

When chaining .then()'s remember to make them all return a resolved (success) message - except for the last one - as each promise (.then()) needs to have the previous success passed to it...below is perhaps a better explanation from the course I am following...

...We invoke checkInventory(order) which returns a promise.
...We invoke .then() with a success handler.
...Inside the success handler, we create our second promise, but we forget to return it!
...We invoke a second .then(). It’s supposed to handle the logic for the second promise, but since we didn’t return, this .then() is invoked on a promise with the same settled value as the original promise!

Common errors people make

Promise composition allows for much more readable code than the nested callback syntax that preceded it.
However, it can still be easy to make mistakes.
This is two common mistakes people make with promise composition.

1. Code is nested rather than chained.
2. Forgetting to return a promise.

For example, the following code is wrong, but works...

checkInventory(order)
    .then((resolvedValueArray) => {
        processPayment(resolvedValueArray)
            .then((resolvedValueArray) => {
                shipOrder(resolvedValueArray)
                    .then((successMessage) => {
                        console.log(successMessage);
                    });
            });
    });
The code is nested inside itself and each .test() promise runs 'processPayment' or 'shipOrder' but does not return anything.

It should look like this...
checkInventory(order)
    .then((resolvedValueArray) => {
        return processPayment(resolvedValueArray);
    })
    .then((resolvedValueArray) => {
        return shipOrder(resolvedValueArray);
    })
    .then((successMessage) => {
        console.log(successMessage);
    });
So each promise (.then()) is chained and each process is returned until, at least, the last one.

Top

Promise.all()

When done correctly, promise composition is a great way to handle situations where asynchronous operations depend on each other or execution order matters.
What if we’re dealing with multiple promises, but we don’t care about the order?
For example...
consider a house clean, we need our clothes to dry, our trash bins emptied, and the dishwasher to run.
We need all of these tasks to complete but not in any particular order.
Furthermore, since they’re all getting done asynchronously, they should really all be happening at the same time!

To maximize efficiency we should use concurrency, multiple asynchronous operations happening together.
With promises, we can do this with the function Promise.all().
Promise.all() accepts an array of promises as its argument and returns a single promise, eg...
Promise.all([promise1, promise2, promise3, etc...]);

If every promise in the argument array resolves, the single promise returned from Promise.all() will resolve with an array containing the resolve value from each promise in the argument array.

If any promise from the argument array rejects, the single promise returned from Promise.all() will immediately reject with the reason that promise rejected.


As an example of Promise.all() please see below...

Promise.all([checkSunglasses, checkPants, checkBags])
   .then(onFulfill)
   .catch(onReject);

Where checkSunglasses, checkPants and checkBags are all routines that call a promise routine to check stock numbers.

If they ALL run through okay then a resolve message is passed back for each routine.
If one of the routines failed then a reject message is passed back from the failed routine.


See the two panes below for a small working example.
The file library.js holds the Promise routines and is Exported - then Imported in to app.js which uses them.

Top

library.js

holds the Promise routines and is Exported...

const checkAvailability = (itemName, distributorName) => {
    console.log(`Checking availability 
of ${itemName} at ${distributorName}...`);
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (restockSuccess()) {
                console.log(`${itemName} are in stock 
at ${distributorName}`)
                resolve(itemName);
            } else {
                reject(`Error: ${itemName} is unavailable 
from ${distributorName} at this time.`);
            }
        }, 1000);
    });
};

module.exports = { checkAvailability };

// This is a function that returns true 80% of the time
// We're using it to simulate a request to the distributor 
// being successful this often
function restockSuccess() {
    return (Math.random() > .2);
}

app.js

imports from library.js and uses its routines...

const {checkAvailability} = require('./library.js');

const onFulfill = (itemsArray) => {
  console.log(`Items checked: ${itemsArray}`);
  console.log(`Every item was available from the 
distributor. Placing order now.`);
};

const onReject = (rejectionReason) => {
	console.log(rejectionReason);
};

// Write your code below:
const checkSunglasses = checkAvailability(
"sunglasses", "Favorite Supply Co.");

const checkPants = checkAvailability(
"pants", "Favorite Supply Co.");

const checkBags = checkAvailability("
bags", "Favorite Supply Co.");

let myPromises = Promise.all([checkSunglasses, 
checkPants, checkBags]);
// NOTE
// If you need to use the 'await' command
// (explained in Asynchronous Javascript (pt2) page)
// you would just say
// let myPromises = await Promise.all(...etc)

myPromises
  .then(onFulfill)
  .catch(onReject);

console.log("Will you do it again");

Promise.all([checkSunglasses, checkPants, checkBags])
  .then(onFulfill)
  .catch(onReject);

Top