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.
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);
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...
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)
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."
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."
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);
checkInventory(order).then((mySuccess) => { console.log(mySuccess); }) .catch((myFailure) => { console.log(myFailure); });
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.
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.
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.
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.
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); }
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);